This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch ih in repository https://gitbox.apache.org/repos/asf/camel.git
commit ea60dfbd7efb488b242e06206d18d54e1f2a866f Author: Claus Ibsen <[email protected]> AuthorDate: Thu Nov 20 10:38:13 2025 +0100 CAMEL-22693: Mark up EIP and endpoint headers that are of importance to make tooling, trouble shooting and development easier. --- catalog/camel-catalog/pom.xml | 2 + .../org/apache/camel/catalog/components/file.json | 2 +- .../camel/catalog/main/important-headers.json | 5 + .../org/apache/camel/catalog/models/aggregate.json | 2 +- .../org/apache/camel/catalog/models/split.json | 2 +- .../org/apache/camel/component/file/file.json | 2 +- .../apache/camel/component/file/FileConstants.java | 3 +- .../java/org/apache/camel/spi/Metadata.java | 6 + .../src/main/java/org/apache/camel/Exchange.java | 11 +- .../META-INF/org/apache/camel/model/aggregate.json | 2 +- .../META-INF/org/apache/camel/model/split.json | 2 +- .../org/apache/camel/support/MessageHelper.java | 10 +- .../apache/camel/util/ImportantHeaderUtils.java | 56 +++++++ .../camel/tooling/model/BaseOptionModel.java | 9 + .../org/apache/camel/tooling/model/JsonMapper.java | 5 + .../packaging/EndpointSchemaGeneratorMojo.java | 9 +- .../camel/maven/packaging/SchemaGeneratorMojo.java | 108 ++++++------ .../packaging/UpdateHeaderImportantHelper.java | 185 +++++++++++++++++++++ .../main/java/org/apache/camel/spi/Metadata.java | 6 + 19 files changed, 366 insertions(+), 61 deletions(-) diff --git a/catalog/camel-catalog/pom.xml b/catalog/camel-catalog/pom.xml index d10d30ce8ef5..07c0221c5f75 100644 --- a/catalog/camel-catalog/pom.xml +++ b/catalog/camel-catalog/pom.xml @@ -159,6 +159,8 @@ <goal>update-sensitive-helper</goal> <!-- update mime-types in camel-util --> <goal>update-mime-type-helper</goal> + <!-- update important headers in camel-util --> + <goal>update-important-header-helper</goal> <!-- update names in camel-main --> <goal>update-main-helper</goal> <!-- update test-infra metadata --> diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/file.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/file.json index 5c1806a24571..6a455a342190 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/file.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/file.json @@ -35,7 +35,7 @@ "CamelFileLastModified": { "index": 1, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "long", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "A Long value containing the last modified timestamp of the file.", "constantName": "org.apache.camel.component.file.FileConstants#FILE_LAST_MODIFIED" }, "CamelFileLocalWorkPath": { "index": 2, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "File", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The local work path", "constantName": "org.apache.camel.component.file.FileConstants#FILE_LOCAL_WORK_PATH" }, "CamelFileNameOnly": { "index": 3, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Only the file name (the name with no leading paths).", "constantName": "org.apache.camel.component.file.FileConstants#FILE_NAME_ONLY" }, - "CamelFileName": { "index": 4, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "(producer) Specifies the name of the file to write (relative to the endpoint directory). This name can be a String; a String with a file or simple Language expression; or an Expression object. If it's null then Camel will auto-generate a filename bas [...] + "CamelFileName": { "index": 4, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "important": true, "description": "(producer) Specifies the name of the file to write (relative to the endpoint directory). This name can be a String; a String with a file or simple Language expression; or an Expression object. If it's null then Camel will auto-gene [...] "CamelFileNameConsumed": { "index": 5, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The name of the file that has been consumed", "constantName": "org.apache.camel.component.file.FileConstants#FILE_NAME_CONSUMED" }, "CamelFileAbsolute": { "index": 6, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "Boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "A boolean option specifying whether the consumed file denotes an absolute path or not. Should normally be false for relative paths. Absolute paths should normally not be used but we added to the move option to allow moving files to abs [...] "CamelFileAbsolutePath": { "index": 7, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The absolute path to the file. For relative files this path holds the relative path instead.", "constantName": "org.apache.camel.component.file.FileConstants#FILE_ABSOLUTE_PATH" }, diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/important-headers.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/important-headers.json new file mode 100644 index 000000000000..c5b0e2b95375 --- /dev/null +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/important-headers.json @@ -0,0 +1,5 @@ +[ + "CamelAggregatedSize", + "CamelFileName", + "CamelSplitSize" +] diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/aggregate.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/aggregate.json index 2aba013108c2..e4ff73c425d2 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/aggregate.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/aggregate.json @@ -46,7 +46,7 @@ "outputs": { "index": 31, "kind": "element", "displayName": "Outputs", "group": "common", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "convertVariableTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "ma [...] }, "exchangeProperties": { - "CamelAggregatedSize": { "index": 0, "kind": "exchangeProperty", "displayName": "Aggregated Size", "label": "producer", "required": false, "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "description": "Number of exchanges that was grouped together." }, + "CamelAggregatedSize": { "index": 0, "kind": "exchangeProperty", "displayName": "Aggregated Size", "label": "producer", "required": false, "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "important": true, "description": "Number of exchanges that was grouped together." }, "CamelAggregatedTimeout": { "index": 1, "kind": "exchangeProperty", "displayName": "Aggregated Timeout", "label": "producer", "required": false, "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "description": "The time in millis this group will timeout" }, "CamelAggregatedCompletedBy": { "index": 2, "kind": "exchangeProperty", "displayName": "Aggregated Completed By", "label": "producer", "required": false, "javaType": "String", "deprecated": false, "autowired": false, "secret": false, "description": "Enum that tell how this group was completed" }, "CamelAggregatedCorrelationKey": { "index": 3, "kind": "exchangeProperty", "displayName": "Aggregated Correlation Key", "label": "producer", "required": false, "javaType": "String", "deprecated": false, "autowired": false, "secret": false, "description": "The correlation key for this aggregation group" }, diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/split.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/split.json index b7f0032927af..198495663989 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/split.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/split.json @@ -35,6 +35,6 @@ "exchangeProperties": { "CamelSplitIndex": { "index": 0, "kind": "exchangeProperty", "displayName": "Split Index", "label": "producer", "required": false, "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "description": "A split counter that increases for each Exchange being split. The counter starts from 0." }, "CamelSplitComplete": { "index": 1, "kind": "exchangeProperty", "displayName": "Split Complete", "label": "producer", "required": false, "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "description": "Whether this Exchange is the last." }, - "CamelSplitSize": { "index": 2, "kind": "exchangeProperty", "displayName": "Split Size", "label": "producer", "required": false, "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "description": "The total number of Exchanges that was split. This property is not applied for stream based splitting, except for the very last message because then Camel knows the total size." } + "CamelSplitSize": { "index": 2, "kind": "exchangeProperty", "displayName": "Split Size", "label": "producer", "required": false, "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "important": true, "description": "The total number of Exchanges that was split. This property is not applied for stream based splitting, except for the very last message because then Camel knows the total size." } } } diff --git a/components/camel-file/src/generated/resources/META-INF/org/apache/camel/component/file/file.json b/components/camel-file/src/generated/resources/META-INF/org/apache/camel/component/file/file.json index 5c1806a24571..6a455a342190 100644 --- a/components/camel-file/src/generated/resources/META-INF/org/apache/camel/component/file/file.json +++ b/components/camel-file/src/generated/resources/META-INF/org/apache/camel/component/file/file.json @@ -35,7 +35,7 @@ "CamelFileLastModified": { "index": 1, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "long", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "A Long value containing the last modified timestamp of the file.", "constantName": "org.apache.camel.component.file.FileConstants#FILE_LAST_MODIFIED" }, "CamelFileLocalWorkPath": { "index": 2, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "File", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The local work path", "constantName": "org.apache.camel.component.file.FileConstants#FILE_LOCAL_WORK_PATH" }, "CamelFileNameOnly": { "index": 3, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Only the file name (the name with no leading paths).", "constantName": "org.apache.camel.component.file.FileConstants#FILE_NAME_ONLY" }, - "CamelFileName": { "index": 4, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "(producer) Specifies the name of the file to write (relative to the endpoint directory). This name can be a String; a String with a file or simple Language expression; or an Expression object. If it's null then Camel will auto-generate a filename bas [...] + "CamelFileName": { "index": 4, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "important": true, "description": "(producer) Specifies the name of the file to write (relative to the endpoint directory). This name can be a String; a String with a file or simple Language expression; or an Expression object. If it's null then Camel will auto-gene [...] "CamelFileNameConsumed": { "index": 5, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The name of the file that has been consumed", "constantName": "org.apache.camel.component.file.FileConstants#FILE_NAME_CONSUMED" }, "CamelFileAbsolute": { "index": 6, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "Boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "A boolean option specifying whether the consumed file denotes an absolute path or not. Should normally be false for relative paths. Absolute paths should normally not be used but we added to the move option to allow moving files to abs [...] "CamelFileAbsolutePath": { "index": 7, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The absolute path to the file. For relative files this path holds the relative path instead.", "constantName": "org.apache.camel.component.file.FileConstants#FILE_ABSOLUTE_PATH" }, diff --git a/components/camel-file/src/main/java/org/apache/camel/component/file/FileConstants.java b/components/camel-file/src/main/java/org/apache/camel/component/file/FileConstants.java index f40236901874..027fd8a5e59a 100644 --- a/components/camel-file/src/main/java/org/apache/camel/component/file/FileConstants.java +++ b/components/camel-file/src/main/java/org/apache/camel/component/file/FileConstants.java @@ -36,7 +36,8 @@ public final class FileConstants { + " `null` then Camel will auto-generate a filename based on the message" + " unique ID. (consumer) Name of the consumed file as a relative file path with offset from the" + " starting directory configured on the endpoint.", - javaType = "String") + javaType = "String", + important = true) public static final String FILE_NAME = Exchange.FILE_NAME; @Metadata(label = "consumer", description = "The name of the file that has been consumed", javaType = "String") public static final String FILE_NAME_CONSUMED = Exchange.FILE_NAME_CONSUMED; diff --git a/core/camel-api/src/generated/java/org/apache/camel/spi/Metadata.java b/core/camel-api/src/generated/java/org/apache/camel/spi/Metadata.java index 462df3cc4dca..c396d77fd2da 100644 --- a/core/camel-api/src/generated/java/org/apache/camel/spi/Metadata.java +++ b/core/camel-api/src/generated/java/org/apache/camel/spi/Metadata.java @@ -175,4 +175,10 @@ public @interface Metadata { * Annotations data for Camel concepts such as components, EIP, etc. */ String[] annotations() default {}; + + /** + * Whether this option is important + */ + boolean important() default false; + } diff --git a/core/camel-api/src/main/java/org/apache/camel/Exchange.java b/core/camel-api/src/main/java/org/apache/camel/Exchange.java index 884d2e35904b..68684368c130 100644 --- a/core/camel-api/src/main/java/org/apache/camel/Exchange.java +++ b/core/camel-api/src/main/java/org/apache/camel/Exchange.java @@ -70,7 +70,8 @@ public interface Exchange extends VariableAware { String AUTHENTICATION = "CamelAuthentication"; String AUTHENTICATION_FAILURE_POLICY_ID = "CamelAuthenticationFailurePolicyId"; - @Metadata(label = "aggregate", description = "Number of exchanges that was grouped together.", javaType = "int") + @Metadata(label = "aggregate", description = "Number of exchanges that was grouped together.", javaType = "int", + important = true) String AGGREGATED_SIZE = "CamelAggregatedSize"; @Metadata(label = "aggregate", description = "The time in millis this group will timeout", javaType = "long") String AGGREGATED_TIMEOUT = "CamelAggregatedTimeout"; @@ -112,6 +113,7 @@ public interface Exchange extends VariableAware { String CLAIM_CHECK_REPOSITORY = "CamelClaimCheckRepository"; String CONTENT_ENCODING = "Content-Encoding"; String CONTENT_LENGTH = "Content-Length"; + @Metadata(important = true) String CONTENT_TYPE = "Content-Type"; String COOKIE_HANDLER = "CamelCookieHandler"; String CORRELATION_ID = "CamelCorrelationId"; @@ -130,7 +132,6 @@ public interface Exchange extends VariableAware { description = "Whether this exchange is a duplicate detected by the Idempotent Consumer EIP", javaType = "boolean") String DUPLICATE_MESSAGE = "CamelDuplicateMessage"; - String DOCUMENT_BUILDER_FACTORY = "CamelDocumentBuilderFactory"; @Metadata(label = "doCatch,doFinally,errorHandler,onException", @@ -154,6 +155,7 @@ public interface Exchange extends VariableAware { String FATAL_FALLBACK_ERROR_HANDLER = "CamelFatalFallbackErrorHandler"; String FILE_CONTENT_TYPE = "CamelFileContentType"; String FILE_LOCAL_WORK_PATH = "CamelFileLocalWorkPath"; + @Metadata(important = true) String FILE_NAME = "CamelFileName"; String FILE_NAME_ONLY = "CamelFileNameOnly"; String FILE_NAME_PRODUCED = "CamelFileNameProduced"; @@ -182,6 +184,7 @@ public interface Exchange extends VariableAware { String HTTP_PROTOCOL_VERSION = "CamelHttpProtocolVersion"; String HTTP_QUERY = "CamelHttpQuery"; String HTTP_RAW_QUERY = "CamelHttpRawQuery"; + @Metadata(important = true) String HTTP_RESPONSE_CODE = "CamelHttpResponseCode"; String HTTP_RESPONSE_TEXT = "CamelHttpResponseText"; String HTTP_URI = "CamelHttpUri"; @@ -277,11 +280,13 @@ public interface Exchange extends VariableAware { String SPLIT_COMPLETE = "CamelSplitComplete"; @Metadata(label = "split", description = "The total number of Exchanges that was split. This property is not applied for stream based splitting, except for the very last message because then Camel knows the total size.", - javaType = "int") + javaType = "int", + important = true) String SPLIT_SIZE = "CamelSplitSize"; @Metadata(label = "step", description = "The id of the Step EIP", javaType = "String") String STEP_ID = "CamelStepId"; + @Metadata(important = true) String TIMER_COUNTER = "CamelTimerCounter"; String TIMER_FIRED_TIME = "CamelTimerFiredTime"; String TIMER_NAME = "CamelTimerName"; diff --git a/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/aggregate.json b/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/aggregate.json index 2aba013108c2..e4ff73c425d2 100644 --- a/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/aggregate.json +++ b/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/aggregate.json @@ -46,7 +46,7 @@ "outputs": { "index": 31, "kind": "element", "displayName": "Outputs", "group": "common", "required": true, "type": "array", "javaType": "java.util.List", "oneOf": [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "convertVariableTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "ma [...] }, "exchangeProperties": { - "CamelAggregatedSize": { "index": 0, "kind": "exchangeProperty", "displayName": "Aggregated Size", "label": "producer", "required": false, "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "description": "Number of exchanges that was grouped together." }, + "CamelAggregatedSize": { "index": 0, "kind": "exchangeProperty", "displayName": "Aggregated Size", "label": "producer", "required": false, "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "important": true, "description": "Number of exchanges that was grouped together." }, "CamelAggregatedTimeout": { "index": 1, "kind": "exchangeProperty", "displayName": "Aggregated Timeout", "label": "producer", "required": false, "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "description": "The time in millis this group will timeout" }, "CamelAggregatedCompletedBy": { "index": 2, "kind": "exchangeProperty", "displayName": "Aggregated Completed By", "label": "producer", "required": false, "javaType": "String", "deprecated": false, "autowired": false, "secret": false, "description": "Enum that tell how this group was completed" }, "CamelAggregatedCorrelationKey": { "index": 3, "kind": "exchangeProperty", "displayName": "Aggregated Correlation Key", "label": "producer", "required": false, "javaType": "String", "deprecated": false, "autowired": false, "secret": false, "description": "The correlation key for this aggregation group" }, diff --git a/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/split.json b/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/split.json index b7f0032927af..198495663989 100644 --- a/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/split.json +++ b/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/split.json @@ -35,6 +35,6 @@ "exchangeProperties": { "CamelSplitIndex": { "index": 0, "kind": "exchangeProperty", "displayName": "Split Index", "label": "producer", "required": false, "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "description": "A split counter that increases for each Exchange being split. The counter starts from 0." }, "CamelSplitComplete": { "index": 1, "kind": "exchangeProperty", "displayName": "Split Complete", "label": "producer", "required": false, "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "description": "Whether this Exchange is the last." }, - "CamelSplitSize": { "index": 2, "kind": "exchangeProperty", "displayName": "Split Size", "label": "producer", "required": false, "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "description": "The total number of Exchanges that was split. This property is not applied for stream based splitting, except for the very last message because then Camel knows the total size." } + "CamelSplitSize": { "index": 2, "kind": "exchangeProperty", "displayName": "Split Size", "label": "producer", "required": false, "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "important": true, "description": "The total number of Exchanges that was split. This property is not applied for stream based splitting, except for the very last message because then Camel knows the total size." } } } diff --git a/core/camel-support/src/main/java/org/apache/camel/support/MessageHelper.java b/core/camel-support/src/main/java/org/apache/camel/support/MessageHelper.java index c0987d91feb3..bcbe22c5313f 100644 --- a/core/camel-support/src/main/java/org/apache/camel/support/MessageHelper.java +++ b/core/camel-support/src/main/java/org/apache/camel/support/MessageHelper.java @@ -40,6 +40,7 @@ import org.apache.camel.spi.DataTypeAware; import org.apache.camel.spi.ExchangeFormatter; import org.apache.camel.spi.HeaderFilterStrategy; import org.apache.camel.trait.message.MessageTrait; +import org.apache.camel.util.ImportantHeaderUtils; import org.apache.camel.util.ObjectHelper; import org.apache.camel.util.StringHelper; import org.apache.camel.util.URISupport; @@ -1009,6 +1010,9 @@ public final class MessageHelper { if (type != null) { jh.put("type", type); } + if (ImportantHeaderUtils.isImportantHeader(key)) { + jh.put("important", true); + } if (value != null) { Object s = Jsoner.trySerialize(value); if (s == null) { @@ -1039,10 +1043,14 @@ public final class MessageHelper { Object value = entry.getValue(); String type = ObjectHelper.classCanonicalName(value); JsonObject jh = new JsonObject(); - jh.put("key", entry.getKey()); + String key = entry.getKey(); + jh.put("key", key); if (type != null) { jh.put("type", type); } + if (ImportantHeaderUtils.isImportantHeader(key)) { + jh.put("important", true); + } // dump header value as JSon, use Camel type converter to convert to String if (value != null) { Object s = Jsoner.trySerialize(value); diff --git a/core/camel-util/src/main/java/org/apache/camel/util/ImportantHeaderUtils.java b/core/camel-util/src/main/java/org/apache/camel/util/ImportantHeaderUtils.java new file mode 100644 index 000000000000..1861151acf70 --- /dev/null +++ b/core/camel-util/src/main/java/org/apache/camel/util/ImportantHeaderUtils.java @@ -0,0 +1,56 @@ +/* + * 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.util; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +public final class ImportantHeaderUtils { + + private static final Set<String> IMPORTANT_HEADER_KEYS = Collections.unmodifiableSet(new HashSet<>( + Arrays.asList( + // Generated by camel build tools - do NOT edit this list! + // IMPORTANT-HEADER-KEYS: START + "CamelAggregatedSize", + "CamelFileName", + "CamelSplitSize" + // IMPORTANT-HEADER-KEYS: END + ))); + + private ImportantHeaderUtils() { + } + + /** + * All the important header keys (unmodifiable) + */ + public static Set<String> getImportantHeaderKeys() { + return IMPORTANT_HEADER_KEYS; + } + + /** + * Whether the given header or exchange properties is marked as important. + * + * @param key the header key + * @return true if important, false otherwise + */ + public static boolean isImportantHeader(String key) { + return IMPORTANT_HEADER_KEYS.contains(key); + } + +} diff --git a/tooling/camel-tooling-model/src/main/java/org/apache/camel/tooling/model/BaseOptionModel.java b/tooling/camel-tooling-model/src/main/java/org/apache/camel/tooling/model/BaseOptionModel.java index 71357d233ef6..29d013d415dc 100644 --- a/tooling/camel-tooling-model/src/main/java/org/apache/camel/tooling/model/BaseOptionModel.java +++ b/tooling/camel-tooling-model/src/main/java/org/apache/camel/tooling/model/BaseOptionModel.java @@ -51,6 +51,7 @@ public abstract class BaseOptionModel { protected boolean supportFileReference; protected boolean largeInput; protected String inputLanguage; + protected boolean important; // todo: move this as a helper method protected boolean newGroup; // special for documentation rendering @@ -303,6 +304,14 @@ public abstract class BaseOptionModel { this.inputLanguage = inputLanguage; } + public boolean isImportant() { + return important; + } + + public void setImportant(boolean important) { + this.important = important; + } + public String getShortGroup() { if (group != null && group.endsWith(" (advanced)")) { return group.substring(0, group.length() - 11); diff --git a/tooling/camel-tooling-model/src/main/java/org/apache/camel/tooling/model/JsonMapper.java b/tooling/camel-tooling-model/src/main/java/org/apache/camel/tooling/model/JsonMapper.java index 8256bc9caa83..eed5132c919c 100644 --- a/tooling/camel-tooling-model/src/main/java/org/apache/camel/tooling/model/JsonMapper.java +++ b/tooling/camel-tooling-model/src/main/java/org/apache/camel/tooling/model/JsonMapper.java @@ -598,6 +598,7 @@ public final class JsonMapper { option.setSupportFileReference(mp.getBooleanOrDefault("supportFileReference", false)); option.setLargeInput(mp.getBooleanOrDefault("largeInput", false)); option.setInputLanguage(mp.getString("inputLanguage")); + option.setImportant(mp.getBooleanOrDefault("important", false)); } private static void parseGroup(JsonObject mp, MainGroupModel option) { @@ -733,6 +734,10 @@ public final class JsonMapper { // only include if supported to not regen all files prop.put("inputLanguage", option.getInputLanguage()); } + if (option.isImportant()) { + // only include if supported to not regen all files + prop.put("important", option.isImportant()); + } prop.put("asPredicate", option.isAsPredicate()); prop.put("configurationClass", option.getConfigurationClass()); prop.put("configurationField", option.getConfigurationField()); diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/EndpointSchemaGeneratorMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/EndpointSchemaGeneratorMojo.java index ea8b56bd145c..02fc1ba522c2 100644 --- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/EndpointSchemaGeneratorMojo.java +++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/EndpointSchemaGeneratorMojo.java @@ -403,7 +403,6 @@ public class EndpointSchemaGeneratorMojo extends AbstractGeneratorMojo { private boolean addEndpointHeader(ComponentModel componentModel, String scheme, Field field, String headersNameProvider) { final Metadata metadata = field.getAnnotation(Metadata.class); if (metadata == null) { - if (getLog().isDebugEnabled()) { getLog().debug(String.format("The field %s in class %s has no Metadata", field.getName(), field.getDeclaringClass().getName())); @@ -412,7 +411,6 @@ public class EndpointSchemaGeneratorMojo extends AbstractGeneratorMojo { } final String[] applicableFor = metadata.applicableFor(); if (applicableFor.length > 0 && Arrays.stream(applicableFor).noneMatch(s -> s.equals(scheme))) { - if (getLog().isDebugEnabled()) { getLog().debug(String.format("The field %s in class %s is not applicable for %s", field.getName(), field.getDeclaringClass().getName(), scheme)); @@ -436,6 +434,7 @@ public class EndpointSchemaGeneratorMojo extends AbstractGeneratorMojo { header.setGroup(EndpointHelper.labelAsGroupName(metadata.label(), componentModel.isConsumerOnly(), componentModel.isProducerOnly())); header.setLabel(metadata.label()); + header.setImportant(metadata.important()); try { header.setEnums(getEnums(metadata, header.getJavaType().isEmpty() ? null : loadClass(header.getJavaType()))); } catch (NoClassDefFoundError e) { @@ -1000,6 +999,7 @@ public class EndpointSchemaGeneratorMojo extends AbstractGeneratorMojo { boolean supportFileReference = metadata != null && metadata.supportFileReference(); boolean largeInput = metadata != null && metadata.largeInput(); String inputLanguage = metadata != null ? metadata.inputLanguage() : null; + boolean important = metadata != null && metadata.important(); // we do not yet have default values / notes / as no annotation // support yet @@ -1118,6 +1118,7 @@ public class EndpointSchemaGeneratorMojo extends AbstractGeneratorMojo { option.setSupportFileReference(supportFileReference); option.setLargeInput(largeInput); option.setInputLanguage(inputLanguage); + option.setImportant(important); componentModel.addComponentOption(option); } } @@ -1375,6 +1376,7 @@ public class EndpointSchemaGeneratorMojo extends AbstractGeneratorMojo { boolean isSecret = secret != null && secret || param.secret(); boolean isAutowired = metadata != null && metadata.autowired(); boolean supportFileReference = metadata != null && metadata.supportFileReference(); + boolean important = metadata != null && metadata.important(); String group = EndpointHelper.labelAsGroupName(label, componentModel.isConsumerOnly(), componentModel.isProducerOnly()); @@ -1431,6 +1433,7 @@ public class EndpointSchemaGeneratorMojo extends AbstractGeneratorMojo { option.setOptionalPrefix(paramOptionalPrefix); option.setMultiValue(multiValue); option.setSupportFileReference(supportFileReference); + option.setImportant(important); if (componentOption) { option.setKind("property"); componentModel.addComponentOption((ComponentOptionModel) option); @@ -1564,6 +1567,7 @@ public class EndpointSchemaGeneratorMojo extends AbstractGeneratorMojo { boolean isAutowired = metadata != null && metadata.autowired(); boolean supportFileReference = metadata != null && metadata.supportFileReference(); boolean largeInput = metadata != null && metadata.largeInput(); + boolean important = metadata != null && metadata.important(); String inputLanguage = metadata != null ? metadata.inputLanguage() : null; String group = EndpointHelper.labelAsGroupName(label, componentModel.isConsumerOnly(), componentModel.isProducerOnly()); @@ -1619,6 +1623,7 @@ public class EndpointSchemaGeneratorMojo extends AbstractGeneratorMojo { option.setSupportFileReference(supportFileReference); option.setLargeInput(largeInput); option.setInputLanguage(inputLanguage); + option.setImportant(important); if (componentModel.getEndpointOptions().stream().noneMatch(opt -> name.equals(opt.getName()))) { componentModel.addEndpointOption((EndpointOptionModel) option); } diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/SchemaGeneratorMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/SchemaGeneratorMojo.java index 969e8263a1db..a06a20503ae4 100644 --- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/SchemaGeneratorMojo.java +++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/SchemaGeneratorMojo.java @@ -368,6 +368,7 @@ public class SchemaGeneratorMojo extends AbstractGeneratorMojo { String valueName = "Camel" + Character.toUpperCase(n2.charAt(0)) + n2.substring(1); o.setName(valueName); o.setDescription(metadata.description()); + o.setImportant(metadata.important()); if (!metadata.displayName().isEmpty()) { o.setDisplayName(metadata.displayName()); } else { @@ -550,9 +551,11 @@ public class SchemaGeneratorMojo extends AbstractGeneratorMojo { } } + boolean important = false; String displayName = null; if (metadata != null) { displayName = metadata.displayName(); + important = metadata.important(); } boolean deprecated = fieldElement.getAnnotation(Deprecated.class) != null; String deprecationNote = null; @@ -566,7 +569,7 @@ public class SchemaGeneratorMojo extends AbstractGeneratorMojo { EipOptionModel ep = createOption(name, displayName, "attribute", fieldTypeName, required, defaultValue, label, docComment, deprecated, deprecationNote, isEnum, enums, - null, false, isDuration); + null, false, isDuration, important); eipOptions.add(ep); return false; @@ -606,8 +609,10 @@ public class SchemaGeneratorMojo extends AbstractGeneratorMojo { } } + boolean important = false; if (metadata != null) { displayName = metadata.displayName(); + important = metadata.important(); } boolean deprecated = fieldElement.getAnnotation(Deprecated.class) != null; String deprecationNote = null; @@ -621,7 +626,7 @@ public class SchemaGeneratorMojo extends AbstractGeneratorMojo { EipOptionModel ep = createOption(name, displayName, "value", fieldTypeName, required, defaultValue, label, docComment, deprecated, deprecationNote, false, null, - null, false, isDuration); + null, false, isDuration, important); eipOptions.add(ep); } @@ -691,9 +696,11 @@ public class SchemaGeneratorMojo extends AbstractGeneratorMojo { oneOfTypes.add("otherwise"); } + boolean important = false; String displayName = null; if (metadata != null) { displayName = metadata.displayName(); + important = metadata.important(); } boolean deprecated = fieldElement.getAnnotation(Deprecated.class) != null; String deprecationNote = null; @@ -707,7 +714,7 @@ public class SchemaGeneratorMojo extends AbstractGeneratorMojo { EipOptionModel ep = createOption(name, displayName, kind, fieldTypeName, required, defaultValue, label, docComment, deprecated, deprecationNote, isEnum, enums, - oneOfTypes, asPredicate, isDuration); + oneOfTypes, asPredicate, isDuration, important); eipOptions.add(ep); } } @@ -735,10 +742,12 @@ public class SchemaGeneratorMojo extends AbstractGeneratorMojo { oneOfTypes.add(child); } + boolean important = false; String displayName = null; Metadata metadata = fieldElement.getAnnotation(Metadata.class); if (metadata != null) { displayName = metadata.displayName(); + important = metadata.important(); } boolean deprecated = fieldElement.getAnnotation(Deprecated.class) != null; String deprecationNote = null; @@ -753,7 +762,7 @@ public class SchemaGeneratorMojo extends AbstractGeneratorMojo { final String kind = "element"; EipOptionModel ep = createOption(name, displayName, kind, fieldTypeName, required, defaultValue, label, docComment, deprecated, deprecationNote, false, null, oneOfTypes, - false, false); + false, false, important); eipOptions.add(ep); } } @@ -763,13 +772,13 @@ public class SchemaGeneratorMojo extends AbstractGeneratorMojo { EipOptionModel ep = createOption("doCatch", "Do Catch", "element", "java.util.List<org.apache.camel.model.CatchDefinition>", false, "", "", "Catches exceptions as part of a try, catch, finally block", false, - null, false, null, Set.of("doCatch"), false, false); + null, false, null, Set.of("doCatch"), false, false, false); eipOptions.add(ep); ep = createOption("doFinally", "Do Finally", "element", "org.apache.camel.model.FinallyDefinition", false, "", "", "Path traversed when a try, catch, finally block exits", false, - null, false, null, null, false, false); + null, false, null, null, false, false, false); eipOptions.add(ep); } @@ -779,82 +788,75 @@ public class SchemaGeneratorMojo extends AbstractGeneratorMojo { String docComment = findJavaDoc(null, "group", null, classElement, true); EipOptionModel ep = createOption("group", "Group", "attribute", "java.lang.String", false, "", "", docComment, false, null, - false, null, null, false, false); + false, null, null, false, false, false); eipOptions.add(ep); // nodePrefixId docComment = findJavaDoc(null, "nodePrefixId", null, classElement, true); ep = createOption("nodePrefixId", "Node Prefix Id", "attribute", "java.lang.String", false, "", "", docComment, false, null, - false, null, null, false, false); + false, null, null, false, false, false); eipOptions.add(ep); // routeConfigurationId docComment = findJavaDoc(null, "routeConfigurationId", null, classElement, true); ep = createOption("routeConfigurationId", "Route Configuration Id", "attribute", "java.lang.String", false, "", "", docComment, false, null, - false, null, null, false, false); + false, null, null, false, false, false); eipOptions.add(ep); // autoStartup docComment = findJavaDoc(null, "autoStartup", null, classElement, true); ep = createOption("autoStartup", "Auto Startup", "attribute", "java.lang.Boolean", false, "true", "", docComment, false, - null, false, null, null, false, false); + null, false, null, null, false, false, false); eipOptions.add(ep); // startupOrder docComment = findJavaDoc(null, "startupOrder", null, classElement, true); ep = createOption("startupOrder", "Startup Order", "attribute", "java.lang.Integer", false, "", "advanced", docComment, - false, - null, - false, null, null, false, false); + false, null, false, null, null, false, false, false); eipOptions.add(ep); // stream cache docComment = findJavaDoc(null, "streamCache", null, classElement, true); ep = createOption("streamCache", "Stream Cache", "attribute", "java.lang.Boolean", false, "", "", docComment, false, - null, - false, null, null, false, false); + null, false, null, null, false, false, false); eipOptions.add(ep); // trace docComment = findJavaDoc(null, "trace", null, classElement, true); ep = createOption("trace", "Trace", "attribute", "java.lang.Boolean", false, "", "", docComment, false, null, false, - null, - null, false, false); + null, null, false, false, false); eipOptions.add(ep); // message history docComment = findJavaDoc(null, "messageHistory", null, classElement, true); ep = createOption("messageHistory", "Message History", "attribute", "java.lang.Boolean", false, "", "", docComment, - false, null, false, null, null, false, false); + false, null, false, null, null, false, false, false); eipOptions.add(ep); // log mask docComment = findJavaDoc(null, "logMask", null, classElement, true); ep = createOption("logMask", "Log Mask", "attribute", "java.lang.Boolean", false, "false", "", docComment, false, null, - false, null, null, false, false); + false, null, null, false, false, false); eipOptions.add(ep); // delayer docComment = findJavaDoc(null, "delayer", null, classElement, true); ep = createOption("delayer", "Delayer", "attribute", "java.lang.Long", false, "advanced", "", docComment, false, null, - false, - null, null, false, true); + false, null, null, false, true, false); eipOptions.add(ep); // errorHandlerRef docComment = findJavaDoc(null, "errorHandlerRef", null, classElement, true); ep = createOption("errorHandlerRef", "Error Handler", "attribute", "java.lang.String", false, "", "error", docComment, - false, - null, false, null, null, false, false); + false, null, false, null, null, false, false, false); eipOptions.add(ep); // routePolicyRef docComment = findJavaDoc(null, "routePolicyRef", null, classElement, true); ep = createOption("routePolicyRef", "Route Policy", "attribute", "java.lang.String", false, "", "", docComment, false, - null, - false, null, null, false, false); + null, false, null, null, false, false, false); eipOptions.add(ep); // shutdownRoute @@ -863,8 +865,7 @@ public class SchemaGeneratorMojo extends AbstractGeneratorMojo { enums.add("Defer"); docComment = findJavaDoc(null, "shutdownRoute", "Default", classElement, true); ep = createOption("shutdownRoute", "Shutdown Route", "attribute", "org.apache.camel.ShutdownRoute", false, "", - "advanced", - docComment, false, null, true, enums, null, false, false); + "advanced", docComment, false, null, true, enums, null, false, false, false); eipOptions.add(ep); // shutdownRunningTask @@ -874,36 +875,34 @@ public class SchemaGeneratorMojo extends AbstractGeneratorMojo { docComment = findJavaDoc(null, "shutdownRunningTask", "CompleteCurrentTaskOnly", classElement, true); ep = createOption("shutdownRunningTask", "Shutdown Running Task", "attribute", "org.apache.camel.ShutdownRunningTask", false, "", "advanced", docComment, false, null, true, enums, - null, false, false); + null, false, false, false); eipOptions.add(ep); // precondition docComment = findJavaDoc(null, "precondition", null, classElement, true); ep = createOption("precondition", "Precondition", "attribute", "java.lang.String", false, "", "advanced", docComment, - false, - null, false, null, null, false, false); + false, null, false, null, null, false, false, false); eipOptions.add(ep); // error handler docComment = findJavaDoc(null, "errorHandler", null, classElement, true); ep = createOption("errorHandler", "Error Handler", "element", "org.apache.camel.model.ErrorHandlerDefinition", false, "", - "error", docComment, false, - null, false, null, null, false, false); + "error", docComment, false, null, false, null, null, false, false, false); eipOptions.add(ep); // input type docComment = findJavaDoc(null, "inputType", null, classElement, true); ep = createOption("inputType", "Input Type", "element", "org.apache.camel.model.InputTypeDefinition", false, "", "advanced", docComment, false, - null, false, null, null, false, false); + null, false, null, null, false, false, false); eipOptions.add(ep); // output type docComment = findJavaDoc(null, "outputType", null, classElement, true); ep = createOption("outputType", "Output Type", "element", "org.apache.camel.model.OutputTypeDefinition", false, "", "advanced", docComment, false, - null, false, null, null, false, false); + null, false, null, null, false, false, false); eipOptions.add(ep); // input @@ -911,7 +910,7 @@ public class SchemaGeneratorMojo extends AbstractGeneratorMojo { oneOfTypes.add("from"); docComment = findJavaDoc(null, "input", null, classElement, true); ep = createOption("input", "Input", "element", "org.apache.camel.model.FromDefinition", true, "", "", docComment, false, - null, false, null, oneOfTypes, false, false); + null, false, null, oneOfTypes, false, false, false); eipOptions.add(ep); // outputs @@ -935,7 +934,7 @@ public class SchemaGeneratorMojo extends AbstractGeneratorMojo { docComment = findJavaDoc(null, "outputs", null, classElement, true); ep = createOption("outputs", "Outputs", "element", "java.util.List<org.apache.camel.model.ProcessorDefinition<?>>", true, "", "", docComment, false, null, false, null, - oneOfTypes, false, false); + oneOfTypes, false, false, false); eipOptions.add(ep); } @@ -947,21 +946,21 @@ public class SchemaGeneratorMojo extends AbstractGeneratorMojo { String docComment = findJavaDoc(null, "id", null, classElement, true); EipOptionModel ep = createOption("id", "Id", "attribute", "java.lang.String", false, "", "", docComment, false, null, false, - null, null, false, false); + null, null, false, false, false); eipOptions.add(ep); // description docComment = findJavaDoc(null, "description", null, classElement, true); ep = createOption("description", "Description", "attribute", "java.lang.String", false, "", "", docComment, false, null, false, null, null, - false, false); + false, false, false); eipOptions.add(ep); // note docComment = findJavaDoc(null, "note", null, classElement, true); ep = createOption("note", "Note", "attribute", "java.lang.String", false, "", "", docComment, false, null, false, null, null, - false, false); + false, false, false); eipOptions.add(ep); } @@ -982,7 +981,7 @@ public class SchemaGeneratorMojo extends AbstractGeneratorMojo { EipOptionModel ep = createOption("routes", "Routes", "element", fieldTypeName, false, "", "", "Contains the Camel routes", false, null, false, null, oneOfTypes, - false, false); + false, false, false); eipOptions.add(ep); } } @@ -1003,7 +1002,7 @@ public class SchemaGeneratorMojo extends AbstractGeneratorMojo { EipOptionModel ep = createOption("rests", "Rests", "element", fieldTypeName, false, "", "", "Contains the rest services defined using the rest-dsl", false, null, false, - null, oneOfTypes, false, false); + null, oneOfTypes, false, false, false); eipOptions.add(ep); } } @@ -1034,10 +1033,12 @@ public class SchemaGeneratorMojo extends AbstractGeneratorMojo { } else { oneOfTypes = Set.of("setVariable"); } + boolean important = false; String displayName = null; Metadata metadata = fieldElement.getAnnotation(Metadata.class); if (metadata != null) { displayName = metadata.displayName(); + important = metadata.important(); } boolean deprecated = fieldElement.getAnnotation(Deprecated.class) != null; String deprecationNote = null; @@ -1053,7 +1054,7 @@ public class SchemaGeneratorMojo extends AbstractGeneratorMojo { EipOptionModel ep = createOption(name, displayName, kind, typeName, true, "", label, "Contains the " + fieldName + " to be set", deprecated, deprecationNote, - false, null, oneOfTypes, false, false); + false, null, oneOfTypes, false, false, important); eipOptions.add(ep); } } @@ -1084,8 +1085,10 @@ public class SchemaGeneratorMojo extends AbstractGeneratorMojo { if (metadata == null) { metadata = methodElement != null ? methodElement.getAnnotation(Metadata.class) : null; } + boolean important = false; if (metadata != null) { displayName = metadata.displayName(); + important = metadata.important(); } boolean deprecated = false; if (fieldElement != null && fieldElement.getAnnotation(Deprecated.class) != null @@ -1104,7 +1107,7 @@ public class SchemaGeneratorMojo extends AbstractGeneratorMojo { String kind = "element"; EipOptionModel ep = createOption(name, displayName, kind, typeName, true, "", label, "", deprecated, deprecationNote, - false, null, oneOfTypes, false, false); + false, null, oneOfTypes, false, false, important); eipOptions.add(ep); } } @@ -1124,10 +1127,12 @@ public class SchemaGeneratorMojo extends AbstractGeneratorMojo { // gather oneOf which extends any of the output base classes Set<String> oneOfTypes = getOneOfs(ONE_OF_VERBS); + boolean important = false; String displayName = null; Metadata metadata = fieldElement.getAnnotation(Metadata.class); if (metadata != null) { displayName = metadata.displayName(); + important = metadata.important(); } boolean deprecated = fieldElement.getAnnotation(Deprecated.class) != null; String deprecationNote = null; @@ -1141,7 +1146,7 @@ public class SchemaGeneratorMojo extends AbstractGeneratorMojo { String kind = "element"; EipOptionModel ep = createOption(name, displayName, kind, fieldTypeName, true, "", label, docComment, deprecated, - deprecationNote, false, null, oneOfTypes, false, false); + deprecationNote, false, null, oneOfTypes, false, false, important); eipOptions.add(ep); } @@ -1160,10 +1165,12 @@ public class SchemaGeneratorMojo extends AbstractGeneratorMojo { } String fieldTypeName = getTypeName(GenericsUtil.resolveType(originalClassType, fieldElement)); + boolean important = false; String displayName = null; Metadata metadata = fieldElement.getAnnotation(Metadata.class); if (metadata != null) { displayName = metadata.displayName(); + important = metadata.important(); } boolean deprecated = fieldElement.getAnnotation(Deprecated.class) != null; String deprecationNote = null; @@ -1177,7 +1184,7 @@ public class SchemaGeneratorMojo extends AbstractGeneratorMojo { String kind = "element"; EipOptionModel ep = createOption(name, displayName, kind, fieldTypeName, false, "", label, docComment, deprecated, - deprecationNote, false, null, null, false, false); + deprecationNote, false, null, null, false, false, important); // insert before "to" eipOptions.add(ep); } @@ -1213,10 +1220,12 @@ public class SchemaGeneratorMojo extends AbstractGeneratorMojo { // gather oneOf expression/predicates which uses language Set<String> oneOfTypes = getOneOfs(ONE_OF_LANGUAGES); + boolean important = false; String displayName = null; Metadata metadata = fieldElement.getAnnotation(Metadata.class); if (metadata != null) { displayName = metadata.displayName(); + important = metadata.important(); } boolean deprecated = fieldElement.getAnnotation(Deprecated.class) != null; String deprecationNote = null; @@ -1232,7 +1241,7 @@ public class SchemaGeneratorMojo extends AbstractGeneratorMojo { final boolean required = expressionRequired(name); EipOptionModel ep = createOption(name, displayName, kind, fieldTypeName, required, "", label, docComment, deprecated, - deprecationNote, false, null, oneOfTypes, asPredicate, false); + deprecationNote, false, null, oneOfTypes, asPredicate, false, important); eipOptions.add(ep); } } @@ -1275,10 +1284,12 @@ public class SchemaGeneratorMojo extends AbstractGeneratorMojo { // when is predicate boolean asPredicate = true; + boolean important = false; String displayName = null; Metadata metadata = fieldElement.getAnnotation(Metadata.class); if (metadata != null) { displayName = metadata.displayName(); + important = metadata.important(); } boolean deprecated = fieldElement.getAnnotation(Deprecated.class) != null; String deprecationNote = null; @@ -1293,7 +1304,7 @@ public class SchemaGeneratorMojo extends AbstractGeneratorMojo { final String kind = "element"; EipOptionModel ep = createOption(name, displayName, kind, fieldTypeName, false, "", label, docComment, deprecated, deprecationNote, false, null, oneOfTypes, - asPredicate, false); + asPredicate, false, important); eipOptions.add(ep); } } @@ -1407,7 +1418,7 @@ public class SchemaGeneratorMojo extends AbstractGeneratorMojo { String name, String displayName, String kind, String type, boolean required, String defaultValue, String label, String description, boolean deprecated, String deprecationNote, boolean enumType, Set<String> enums, Set<String> oneOfs, boolean asPredicate, - boolean isDuration) { + boolean isDuration, boolean important) { EipOptionModel option = new EipOptionModel(); option.setName(name); option.setDisplayName(Strings.isNullOrEmpty(displayName) ? Strings.asTitle(name) : displayName); @@ -1426,6 +1437,7 @@ public class SchemaGeneratorMojo extends AbstractGeneratorMojo { option.setEnums(enums != null && !enums.isEmpty() ? new ArrayList<>(enums) : null); option.setOneOfs(oneOfs != null && !oneOfs.isEmpty() ? new ArrayList<>(oneOfs) : null); option.setAsPredicate(asPredicate); + option.setImportant(important); return option; } diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/UpdateHeaderImportantHelper.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/UpdateHeaderImportantHelper.java new file mode 100644 index 000000000000..7cbd21e70725 --- /dev/null +++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/UpdateHeaderImportantHelper.java @@ -0,0 +1,185 @@ +/* + * 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.maven.packaging; + +import java.io.File; +import java.nio.file.Path; +import java.util.List; +import java.util.Set; +import java.util.StringJoiner; +import java.util.TreeSet; +import java.util.stream.Stream; + +import javax.inject.Inject; + +import org.apache.camel.tooling.model.ComponentModel; +import org.apache.camel.tooling.model.EipModel; +import org.apache.camel.tooling.model.JsonMapper; +import org.apache.camel.tooling.util.PackageHelper; +import org.apache.camel.tooling.util.Strings; +import org.apache.camel.util.json.JsonArray; +import org.apache.camel.util.json.JsonObject; +import org.apache.camel.util.json.Jsoner; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.project.MavenProjectHelper; +import org.codehaus.plexus.build.BuildContext; + +import static org.apache.camel.tooling.util.PackageHelper.findCamelDirectory; + +/** + * Updates the HeaderImportantHelper.java with the known important message headers + */ +@Mojo(name = "update-important-header-helper", threadSafe = true) +public class UpdateHeaderImportantHelper extends AbstractGeneratorMojo { + + private static final String KEYS_START_TOKEN = "// IMPORTANT-HEADER-KEYS: START"; + private static final String KEYS_END_TOKEN = "// IMPORTANT-HEADER-KEYS: END"; + + @Parameter(defaultValue = "${project.basedir}/src/generated/resources/org/apache/camel/catalog/") + protected File jsonDir; + + @Parameter(defaultValue = "${project.basedir}/") + protected File baseDir; + + @Inject + public UpdateHeaderImportantHelper(MavenProjectHelper projectHelper, BuildContext buildContext) { + super(projectHelper, buildContext); + } + + /** + * Execute goal. + * + * @throws MojoExecutionException execution of the main class or one of the threads it generated failed. + */ + @Override + public void execute() throws MojoExecutionException { + File camelDir = findCamelDirectory(baseDir, "core/camel-util"); + if (camelDir == null) { + getLog().debug("No core/camel-util folder found, skipping execution"); + return; + } + List<Path> jsonFiles; + try (Stream<Path> stream = PackageHelper.findJsonFiles(jsonDir.toPath())) { + jsonFiles = stream.toList(); + } + Set<String> importants = new TreeSet<>(); + + for (Path file : jsonFiles) { + final String name = PackageHelper.asName(file); + + try { + String json = PackageHelper.loadText(file.toFile()); + Object jo = Jsoner.deserialize(json); + JsonObject obj; + if (jo instanceof JsonObject) { + obj = (JsonObject) jo; + } else { + continue; + } + + boolean isComponent = obj.getMap("component") != null; + boolean isEip = !isComponent && obj.getMap("model") != null; + + // only check these kind + if (!isComponent && !isEip) { + continue; + } + + if (isComponent) { + ComponentModel cm = JsonMapper.generateComponentModel(json); + cm.getEndpointHeaders().forEach(o -> { + if (o.isImportant()) { + importants.add(o.getName()); + } + }); + } else if (isEip) { + EipModel em = JsonMapper.generateEipModel(json); + em.getExchangeProperties().forEach(o -> { + if (o.isImportant()) { + importants.add(o.getName()); + } + }); + } + } catch (Exception e) { + throw new MojoExecutionException("Error loading json: " + name, e); + } + } + + getLog().info("There are " + importants.size() + + " distinct important options across all the Camel components/eips"); + + try { + boolean updated = updateImportantHeaderKeys(camelDir, importants); + if (updated) { + getLog().info("Updated camel-util/src/main/java/org/apache/camel/util/ImportantHeaderUtils.java file"); + } else { + getLog().debug("No changes to camel-util/src/main/java/org/apache/camel/util/ImportantHeaderUtils.java file"); + } + } catch (Exception e) { + throw new MojoExecutionException("Error updating ImportantHeaderUtils.java", e); + } + + try { + updateImportantHeaderJsonSchema(baseDir, importants); + } catch (Exception e) { + throw new MojoExecutionException("Error updating important-headers.json", e); + } + } + + private boolean updateImportantHeaderKeys(File camelDir, Set<String> importants) throws Exception { + // load source code and update + File java = new File(camelDir, "src/main/java/org/apache/camel/util/ImportantHeaderUtils.java"); + String text = PackageHelper.loadText(java); + String spaces20 = " "; + String spaces12 = " "; + + StringJoiner sb = new StringJoiner(",\n"); + for (String name : importants) { + sb.add(spaces20 + "\"" + name + "\""); + } + String changed = sb.toString(); + + String existing = Strings.between(text, KEYS_START_TOKEN, KEYS_END_TOKEN); + if (existing != null) { + // remove leading line breaks etc + existing = existing.trim(); + changed = changed.trim(); + if (existing.equals(changed)) { + return false; + } else { + String before = Strings.before(text, KEYS_START_TOKEN); + String after = Strings.after(text, KEYS_END_TOKEN); + text = before + KEYS_START_TOKEN + "\n" + spaces20 + changed + "\n" + spaces12 + KEYS_END_TOKEN + after; + PackageHelper.writeText(java, text); + return true; + } + } + + return false; + } + + private void updateImportantHeaderJsonSchema(File camelDir, Set<String> secrets) throws Exception { + File target = new File(camelDir, "src/generated/resources/org/apache/camel/catalog/main/important-headers.json"); + JsonArray arr = new JsonArray(); + arr.addAll(secrets); + String json = JsonMapper.serialize(arr); + PackageHelper.writeText(target, json); + } + +} diff --git a/tooling/spi-annotations/src/main/java/org/apache/camel/spi/Metadata.java b/tooling/spi-annotations/src/main/java/org/apache/camel/spi/Metadata.java index 462df3cc4dca..c396d77fd2da 100644 --- a/tooling/spi-annotations/src/main/java/org/apache/camel/spi/Metadata.java +++ b/tooling/spi-annotations/src/main/java/org/apache/camel/spi/Metadata.java @@ -175,4 +175,10 @@ public @interface Metadata { * Annotations data for Camel concepts such as components, EIP, etc. */ String[] annotations() default {}; + + /** + * Whether this option is important + */ + boolean important() default false; + }
