This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch feature/CAMEL-25652-internal-flag in repository https://gitbox.apache.org/repos/asf/camel.git
commit 66aa4814f05a009da58cd00f9dbd0e7d344467ae Author: Claus Ibsen <[email protected]> AuthorDate: Wed Oct 14 15:03:02 2026 +0200 CAMEL-25652: Component metadata - an internal flag, next to remote, for components that only reach the CamelContext @UriEndpoint(internal = true) marks a component that stays inside the CamelContext: its routes, in-memory state and log, and never a file, the network, a process, or code or a resource named in its URI. A capability counts even behind a seldom used option or a feature the component ships with. It implies remote = false (the build fails otherwise). The catalog JSON has "internal": true on the 13 internal components only (direct, seda, stub, disruptor, disruptor-vm, log, mock, browse, caffeine-cache, caffeine-loadcache, metrics, event, timer), and ComponentModel.isInternal(). The AI tools of the TUI read it from the catalog instead of their own list; dataset-test now asks first. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]> Signed-off-by: Claus Ibsen <[email protected]> --- .../apache/camel/catalog/components/browse.json | 3 +- .../camel/catalog/components/caffeine-cache.json | 3 +- .../catalog/components/caffeine-loadcache.json | 3 +- .../apache/camel/catalog/components/direct.json | 3 +- .../camel/catalog/components/disruptor-vm.json | 3 +- .../apache/camel/catalog/components/disruptor.json | 3 +- .../org/apache/camel/catalog/components/event.json | 3 +- .../org/apache/camel/catalog/components/log.json | 3 +- .../apache/camel/catalog/components/metrics.json | 3 +- .../org/apache/camel/catalog/components/mock.json | 3 +- .../org/apache/camel/catalog/components/seda.json | 3 +- .../org/apache/camel/catalog/components/stub.json | 3 +- .../org/apache/camel/catalog/components/timer.json | 3 +- .../org/apache/camel/catalog/CamelCatalogTest.java | 14 ++++++++ .../org/apache/camel/component/browse/browse.json | 3 +- .../camel/component/browse/BrowseEndpoint.java | 2 +- .../component/caffeine/cache/caffeine-cache.json | 3 +- .../caffeine/load/caffeine-loadcache.json | 3 +- .../caffeine/cache/CaffeineCacheEndpoint.java | 3 +- .../caffeine/load/CaffeineLoadCacheEndpoint.java | 3 +- .../org/apache/camel/component/direct/direct.json | 3 +- .../camel/component/direct/DirectEndpoint.java | 2 +- .../camel/component/disruptor/disruptor-vm.json | 3 +- .../camel/component/disruptor/disruptor.json | 3 +- .../component/disruptor/DisruptorEndpoint.java | 2 +- .../apache/camel/component/camelevent/event.json | 3 +- .../component/camelevent/CamelEventEndpoint.java | 2 +- .../org/apache/camel/component/log/log.json | 3 +- .../apache/camel/component/log/LogEndpoint.java | 3 +- .../apache/camel/component/metrics/metrics.json | 3 +- .../camel/component/metrics/MetricsEndpoint.java | 3 +- .../org/apache/camel/component/mock/mock.json | 3 +- .../apache/camel/component/mock/MockEndpoint.java | 2 +- .../org/apache/camel/component/seda/seda.json | 3 +- .../apache/camel/component/seda/SedaEndpoint.java | 2 +- .../org/apache/camel/component/stub/stub.json | 3 +- .../apache/camel/component/stub/StubEndpoint.java | 2 +- .../org/apache/camel/component/timer/timer.json | 3 +- .../camel/component/timer/TimerEndpoint.java | 3 +- .../java/org/apache/camel/spi/UriEndpoint.java | 22 +++++++++++++ .../modules/ROOT/pages/camel-jbang-tui-ai.adoc | 6 ++-- .../modules/ROOT/pages/security-model.adoc | 5 +-- .../dsl/jbang/core/commands/tui/ToolConfirms.java | 37 ++++++++++++++++------ .../jbang/core/commands/tui/ToolConfirmsTest.java | 13 +++++++- .../apache/camel/tooling/model/ComponentModel.java | 13 ++++++++ .../org/apache/camel/tooling/model/JsonMapper.java | 5 +++ .../apache/camel/tooling/model/JsonMapperTest.java | 13 ++++++++ .../packaging/EndpointSchemaGeneratorMojo.java | 6 ++++ .../packaging/EndpointSchemaGeneratorMojoTest.java | 12 +++++++ .../endpoint/SomeInternalRemoteEndpoint.java | 24 ++++++++++++++ .../java/org/apache/camel/spi/UriEndpoint.java | 22 +++++++++++++ 51 files changed, 247 insertions(+), 52 deletions(-) diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/browse.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/browse.json index 282c9b11e150..208f04911301 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/browse.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/browse.json @@ -21,7 +21,8 @@ "producerOnly": false, "lenientProperties": false, "browsable": true, - "remote": false + "remote": false, + "internal": 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 like [...] diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/caffeine-cache.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/caffeine-cache.json index 4a1f35b7cb1a..2306d19ed008 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/caffeine-cache.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/caffeine-cache.json @@ -21,7 +21,8 @@ "producerOnly": true, "lenientProperties": false, "browsable": false, - "remote": false + "remote": false, + "internal": true }, "componentProperties": { "action": { "index": 0, "kind": "property", "displayName": "Action", "group": "producer", "label": "", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "GET", "GET_ALL", "PUT", "PUT_ALL", "INVALIDATE", "INVALIDATE_ALL", "CLEANUP", "AS_MAP" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.caffeine.CaffeineConfiguration", "configurationField": "configuration", "description": "To configure the defa [...] diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/caffeine-loadcache.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/caffeine-loadcache.json index 0eaeaed09173..0da3d147ff1c 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/caffeine-loadcache.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/caffeine-loadcache.json @@ -21,7 +21,8 @@ "producerOnly": true, "lenientProperties": false, "browsable": false, - "remote": false + "remote": false, + "internal": true }, "componentProperties": { "action": { "index": 0, "kind": "property", "displayName": "Action", "group": "producer", "label": "", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "GET", "GET_ALL", "PUT", "PUT_ALL", "INVALIDATE", "INVALIDATE_ALL", "CLEANUP", "AS_MAP" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.caffeine.CaffeineConfiguration", "configurationField": "configuration", "description": "To configure the defa [...] diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/direct.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/direct.json index e0866218e2e9..bf84bbc045c0 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/direct.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/direct.json @@ -21,7 +21,8 @@ "producerOnly": false, "lenientProperties": false, "browsable": false, - "remote": false + "remote": false, + "internal": 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 like [...] diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/disruptor-vm.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/disruptor-vm.json index 16e4ff1b865f..83bda4488248 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/disruptor-vm.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/disruptor-vm.json @@ -22,7 +22,8 @@ "producerOnly": false, "lenientProperties": false, "browsable": false, - "remote": false + "remote": false, + "internal": true }, "componentProperties": { "bufferSize": { "index": 0, "kind": "property", "displayName": "Buffer Size", "group": "common", "label": "", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 1024, "description": "To configure the ring buffer size" }, diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/disruptor.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/disruptor.json index 90a59fa80dc2..9cf585a052c5 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/disruptor.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/disruptor.json @@ -22,7 +22,8 @@ "producerOnly": false, "lenientProperties": false, "browsable": false, - "remote": false + "remote": false, + "internal": true }, "componentProperties": { "bufferSize": { "index": 0, "kind": "property", "displayName": "Buffer Size", "group": "common", "label": "", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 1024, "description": "To configure the ring buffer size" }, diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/event.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/event.json index 9ef15d1462f1..e0fcda0198bd 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/event.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/event.json @@ -21,7 +21,8 @@ "producerOnly": false, "lenientProperties": false, "browsable": false, - "remote": false + "remote": false, + "internal": 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 like [...] diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/log.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/log.json index 553eac237c7d..30b8b7326c6b 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/log.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/log.json @@ -21,7 +21,8 @@ "producerOnly": true, "lenientProperties": false, "browsable": false, - "remote": false + "remote": false, + "internal": true }, "componentProperties": { "lazyStartProducer": { "index": 0, "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 [...] diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/metrics.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/metrics.json index 6927e608305f..952ca0a8b5d9 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/metrics.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/metrics.json @@ -21,7 +21,8 @@ "producerOnly": true, "lenientProperties": false, "browsable": false, - "remote": false + "remote": false, + "internal": true }, "componentProperties": { "lazyStartProducer": { "index": 0, "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 [...] diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/mock.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/mock.json index f22d774f197c..d8a7f8807de2 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/mock.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/mock.json @@ -21,7 +21,8 @@ "producerOnly": true, "lenientProperties": true, "browsable": true, - "remote": false + "remote": false, + "internal": true }, "componentProperties": { "lazyStartProducer": { "index": 0, "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 [...] diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/seda.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/seda.json index 6681f3cbd6c3..0a1a4bb65b6d 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/seda.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/seda.json @@ -21,7 +21,8 @@ "producerOnly": false, "lenientProperties": false, "browsable": true, - "remote": false + "remote": false, + "internal": 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 like [...] diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/stub.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/stub.json index 32d642f6acce..43c75bea1a28 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/stub.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/stub.json @@ -21,7 +21,8 @@ "producerOnly": false, "lenientProperties": true, "browsable": true, - "remote": false + "remote": false, + "internal": 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 like [...] diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/timer.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/timer.json index 28e78be1017b..88a27c1c699a 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/timer.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/timer.json @@ -21,7 +21,8 @@ "producerOnly": false, "lenientProperties": false, "browsable": false, - "remote": false + "remote": false, + "internal": 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 like [...] diff --git a/catalog/camel-catalog/src/test/java/org/apache/camel/catalog/CamelCatalogTest.java b/catalog/camel-catalog/src/test/java/org/apache/camel/catalog/CamelCatalogTest.java index e868ae64bb34..b167e18c4e83 100644 --- a/catalog/camel-catalog/src/test/java/org/apache/camel/catalog/CamelCatalogTest.java +++ b/catalog/camel-catalog/src/test/java/org/apache/camel/catalog/CamelCatalogTest.java @@ -206,6 +206,20 @@ public class CamelCatalogTest { assertTrue(catalog.componentModel("activemq").getAliases().contains("amq")); } + @Test + public void testComponentInternal() { + // internal: stays inside the CamelContext, set with @UriEndpoint(internal = true) + assertTrue(catalog.componentModel("direct").isInternal()); + assertTrue(catalog.componentModel("log").isInternal()); + assertTrue(catalog.componentModel("disruptor-vm").isInternal()); + assertFalse(catalog.componentModel("kafka").isInternal()); + // not remote, but not internal either: exec runs a process, dataset-test polls the endpoint in its URI + for (String name : List.of("exec", "dataset-test")) { + assertFalse(catalog.componentModel(name).isRemote(), name); + assertFalse(catalog.componentModel(name).isInternal(), name); + } + } + @Test public void testSuggestComponentNames() { // exact scheme first, then words of the title or scheme diff --git a/components/camel-browse/src/generated/resources/META-INF/org/apache/camel/component/browse/browse.json b/components/camel-browse/src/generated/resources/META-INF/org/apache/camel/component/browse/browse.json index 282c9b11e150..208f04911301 100644 --- a/components/camel-browse/src/generated/resources/META-INF/org/apache/camel/component/browse/browse.json +++ b/components/camel-browse/src/generated/resources/META-INF/org/apache/camel/component/browse/browse.json @@ -21,7 +21,8 @@ "producerOnly": false, "lenientProperties": false, "browsable": true, - "remote": false + "remote": false, + "internal": 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 like [...] diff --git a/components/camel-browse/src/main/java/org/apache/camel/component/browse/BrowseEndpoint.java b/components/camel-browse/src/main/java/org/apache/camel/component/browse/BrowseEndpoint.java index e6c657484c92..5462f9dae33f 100644 --- a/components/camel-browse/src/main/java/org/apache/camel/component/browse/BrowseEndpoint.java +++ b/components/camel-browse/src/main/java/org/apache/camel/component/browse/BrowseEndpoint.java @@ -42,7 +42,7 @@ import org.apache.camel.support.DefaultProducer; * available to be browsed. */ @UriEndpoint(firstVersion = "1.3.0", scheme = "browse", title = "Browse", syntax = "browse:name", - remote = false, category = { Category.CORE, Category.MONITORING }) + remote = false, internal = true, category = { Category.CORE, Category.MONITORING }) public class BrowseEndpoint extends DefaultEndpoint implements BrowsableEndpoint { @UriPath(description = "A name which can be any string to uniquely identify the endpoint") diff --git a/components/camel-caffeine/src/generated/resources/META-INF/org/apache/camel/component/caffeine/cache/caffeine-cache.json b/components/camel-caffeine/src/generated/resources/META-INF/org/apache/camel/component/caffeine/cache/caffeine-cache.json index 4a1f35b7cb1a..2306d19ed008 100644 --- a/components/camel-caffeine/src/generated/resources/META-INF/org/apache/camel/component/caffeine/cache/caffeine-cache.json +++ b/components/camel-caffeine/src/generated/resources/META-INF/org/apache/camel/component/caffeine/cache/caffeine-cache.json @@ -21,7 +21,8 @@ "producerOnly": true, "lenientProperties": false, "browsable": false, - "remote": false + "remote": false, + "internal": true }, "componentProperties": { "action": { "index": 0, "kind": "property", "displayName": "Action", "group": "producer", "label": "", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "GET", "GET_ALL", "PUT", "PUT_ALL", "INVALIDATE", "INVALIDATE_ALL", "CLEANUP", "AS_MAP" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.caffeine.CaffeineConfiguration", "configurationField": "configuration", "description": "To configure the defa [...] diff --git a/components/camel-caffeine/src/generated/resources/META-INF/org/apache/camel/component/caffeine/load/caffeine-loadcache.json b/components/camel-caffeine/src/generated/resources/META-INF/org/apache/camel/component/caffeine/load/caffeine-loadcache.json index 0eaeaed09173..0da3d147ff1c 100644 --- a/components/camel-caffeine/src/generated/resources/META-INF/org/apache/camel/component/caffeine/load/caffeine-loadcache.json +++ b/components/camel-caffeine/src/generated/resources/META-INF/org/apache/camel/component/caffeine/load/caffeine-loadcache.json @@ -21,7 +21,8 @@ "producerOnly": true, "lenientProperties": false, "browsable": false, - "remote": false + "remote": false, + "internal": true }, "componentProperties": { "action": { "index": 0, "kind": "property", "displayName": "Action", "group": "producer", "label": "", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "GET", "GET_ALL", "PUT", "PUT_ALL", "INVALIDATE", "INVALIDATE_ALL", "CLEANUP", "AS_MAP" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.caffeine.CaffeineConfiguration", "configurationField": "configuration", "description": "To configure the defa [...] diff --git a/components/camel-caffeine/src/main/java/org/apache/camel/component/caffeine/cache/CaffeineCacheEndpoint.java b/components/camel-caffeine/src/main/java/org/apache/camel/component/caffeine/cache/CaffeineCacheEndpoint.java index 38da56f487fa..8ed4bb8c919c 100644 --- a/components/camel-caffeine/src/main/java/org/apache/camel/component/caffeine/cache/CaffeineCacheEndpoint.java +++ b/components/camel-caffeine/src/main/java/org/apache/camel/component/caffeine/cache/CaffeineCacheEndpoint.java @@ -35,7 +35,8 @@ import org.apache.camel.support.DefaultEndpoint; * Perform caching operations using Caffeine Cache. */ @UriEndpoint(firstVersion = "2.20.0", scheme = "caffeine-cache", title = "Caffeine Cache", - remote = false, syntax = "caffeine-cache:cacheName", category = { Category.CACHE, Category.CLUSTERING }, + remote = false, internal = true, syntax = "caffeine-cache:cacheName", + category = { Category.CACHE, Category.CLUSTERING }, producerOnly = true, headersClass = CaffeineConstants.class) public class CaffeineCacheEndpoint extends DefaultEndpoint { diff --git a/components/camel-caffeine/src/main/java/org/apache/camel/component/caffeine/load/CaffeineLoadCacheEndpoint.java b/components/camel-caffeine/src/main/java/org/apache/camel/component/caffeine/load/CaffeineLoadCacheEndpoint.java index fb8c4acde8cc..755d0b779957 100644 --- a/components/camel-caffeine/src/main/java/org/apache/camel/component/caffeine/load/CaffeineLoadCacheEndpoint.java +++ b/components/camel-caffeine/src/main/java/org/apache/camel/component/caffeine/load/CaffeineLoadCacheEndpoint.java @@ -35,7 +35,8 @@ import org.apache.camel.support.DefaultEndpoint; * Perform caching operations using Caffeine Cache with an attached CacheLoader. */ @UriEndpoint(firstVersion = "2.20.0", scheme = "caffeine-loadcache", title = "Caffeine LoadCache", - remote = false, syntax = "caffeine-loadcache:cacheName", category = { Category.CACHE, Category.CLUSTERING }, + remote = false, internal = true, syntax = "caffeine-loadcache:cacheName", + category = { Category.CACHE, Category.CLUSTERING }, producerOnly = true, headersClass = CaffeineConstants.class) public class CaffeineLoadCacheEndpoint extends DefaultEndpoint { @UriPath(description = "the cache name") diff --git a/components/camel-direct/src/generated/resources/META-INF/org/apache/camel/component/direct/direct.json b/components/camel-direct/src/generated/resources/META-INF/org/apache/camel/component/direct/direct.json index e0866218e2e9..bf84bbc045c0 100644 --- a/components/camel-direct/src/generated/resources/META-INF/org/apache/camel/component/direct/direct.json +++ b/components/camel-direct/src/generated/resources/META-INF/org/apache/camel/component/direct/direct.json @@ -21,7 +21,8 @@ "producerOnly": false, "lenientProperties": false, "browsable": false, - "remote": false + "remote": false, + "internal": 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 like [...] diff --git a/components/camel-direct/src/main/java/org/apache/camel/component/direct/DirectEndpoint.java b/components/camel-direct/src/main/java/org/apache/camel/component/direct/DirectEndpoint.java index 733aa2a71632..1452087ad592 100644 --- a/components/camel-direct/src/main/java/org/apache/camel/component/direct/DirectEndpoint.java +++ b/components/camel-direct/src/main/java/org/apache/camel/component/direct/DirectEndpoint.java @@ -33,7 +33,7 @@ import org.apache.camel.util.StringHelper; * This endpoint can be used to connect existing routes in the same CamelContext. */ @UriEndpoint(firstVersion = "1.0.0", scheme = "direct", title = "Direct", syntax = "direct:name", - remote = false, category = { Category.CORE, Category.MESSAGING }) + remote = false, internal = true, category = { Category.CORE, Category.MESSAGING }) public class DirectEndpoint extends DefaultEndpoint { private final DirectComponent component; diff --git a/components/camel-disruptor/src/generated/resources/META-INF/org/apache/camel/component/disruptor/disruptor-vm.json b/components/camel-disruptor/src/generated/resources/META-INF/org/apache/camel/component/disruptor/disruptor-vm.json index 16e4ff1b865f..83bda4488248 100644 --- a/components/camel-disruptor/src/generated/resources/META-INF/org/apache/camel/component/disruptor/disruptor-vm.json +++ b/components/camel-disruptor/src/generated/resources/META-INF/org/apache/camel/component/disruptor/disruptor-vm.json @@ -22,7 +22,8 @@ "producerOnly": false, "lenientProperties": false, "browsable": false, - "remote": false + "remote": false, + "internal": true }, "componentProperties": { "bufferSize": { "index": 0, "kind": "property", "displayName": "Buffer Size", "group": "common", "label": "", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 1024, "description": "To configure the ring buffer size" }, diff --git a/components/camel-disruptor/src/generated/resources/META-INF/org/apache/camel/component/disruptor/disruptor.json b/components/camel-disruptor/src/generated/resources/META-INF/org/apache/camel/component/disruptor/disruptor.json index 90a59fa80dc2..9cf585a052c5 100644 --- a/components/camel-disruptor/src/generated/resources/META-INF/org/apache/camel/component/disruptor/disruptor.json +++ b/components/camel-disruptor/src/generated/resources/META-INF/org/apache/camel/component/disruptor/disruptor.json @@ -22,7 +22,8 @@ "producerOnly": false, "lenientProperties": false, "browsable": false, - "remote": false + "remote": false, + "internal": true }, "componentProperties": { "bufferSize": { "index": 0, "kind": "property", "displayName": "Buffer Size", "group": "common", "label": "", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 1024, "description": "To configure the ring buffer size" }, diff --git a/components/camel-disruptor/src/main/java/org/apache/camel/component/disruptor/DisruptorEndpoint.java b/components/camel-disruptor/src/main/java/org/apache/camel/component/disruptor/DisruptorEndpoint.java index ab83f1e0dfc1..aa236f9be717 100644 --- a/components/camel-disruptor/src/main/java/org/apache/camel/component/disruptor/DisruptorEndpoint.java +++ b/components/camel-disruptor/src/main/java/org/apache/camel/component/disruptor/DisruptorEndpoint.java @@ -52,7 +52,7 @@ import org.slf4j.LoggerFactory; */ @ManagedResource(description = "Managed Disruptor Endpoint") @UriEndpoint(firstVersion = "2.12.0", scheme = "disruptor,disruptor-vm", title = "Disruptor,Disruptor VM", - remote = false, syntax = "disruptor:name", category = { Category.MESSAGING }) + remote = false, internal = true, syntax = "disruptor:name", category = { Category.MESSAGING }) public class DisruptorEndpoint extends DefaultEndpoint implements AsyncEndpoint, MultipleConsumersSupport { /** * Property on the exchange published by a producer that waits for the reply. Its value is set to true when the diff --git a/components/camel-event/src/generated/resources/META-INF/org/apache/camel/component/camelevent/event.json b/components/camel-event/src/generated/resources/META-INF/org/apache/camel/component/camelevent/event.json index 9ef15d1462f1..e0fcda0198bd 100644 --- a/components/camel-event/src/generated/resources/META-INF/org/apache/camel/component/camelevent/event.json +++ b/components/camel-event/src/generated/resources/META-INF/org/apache/camel/component/camelevent/event.json @@ -21,7 +21,8 @@ "producerOnly": false, "lenientProperties": false, "browsable": false, - "remote": false + "remote": false, + "internal": 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 like [...] diff --git a/components/camel-event/src/main/java/org/apache/camel/component/camelevent/CamelEventEndpoint.java b/components/camel-event/src/main/java/org/apache/camel/component/camelevent/CamelEventEndpoint.java index 528f897f42f3..db7538ca9557 100644 --- a/components/camel-event/src/main/java/org/apache/camel/component/camelevent/CamelEventEndpoint.java +++ b/components/camel-event/src/main/java/org/apache/camel/component/camelevent/CamelEventEndpoint.java @@ -46,7 +46,7 @@ import org.apache.camel.support.DefaultEndpoint; * {@code event:Exchange*} matches all exchange events, and {@code event:*} matches all events. */ @UriEndpoint(firstVersion = "4.19.0", scheme = "event", title = "Event", syntax = "event:events", - consumerOnly = true, remote = false, + consumerOnly = true, remote = false, internal = true, category = { Category.CORE, Category.MONITORING }, headersClass = CamelEventConstants.class) public class CamelEventEndpoint extends DefaultEndpoint { diff --git a/components/camel-log/src/generated/resources/META-INF/org/apache/camel/component/log/log.json b/components/camel-log/src/generated/resources/META-INF/org/apache/camel/component/log/log.json index 553eac237c7d..30b8b7326c6b 100644 --- a/components/camel-log/src/generated/resources/META-INF/org/apache/camel/component/log/log.json +++ b/components/camel-log/src/generated/resources/META-INF/org/apache/camel/component/log/log.json @@ -21,7 +21,8 @@ "producerOnly": true, "lenientProperties": false, "browsable": false, - "remote": false + "remote": false, + "internal": true }, "componentProperties": { "lazyStartProducer": { "index": 0, "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 [...] diff --git a/components/camel-log/src/main/java/org/apache/camel/component/log/LogEndpoint.java b/components/camel-log/src/main/java/org/apache/camel/component/log/LogEndpoint.java index 13e54397b0f6..3f8eff912721 100644 --- a/components/camel-log/src/main/java/org/apache/camel/component/log/LogEndpoint.java +++ b/components/camel-log/src/main/java/org/apache/camel/component/log/LogEndpoint.java @@ -43,7 +43,8 @@ import static org.apache.camel.support.LoggerHelper.getLineNumberLoggerName; * Prints data from the routed message (such as body and headers) to the logger. */ @UriEndpoint(firstVersion = "1.1.0", scheme = "log", title = "Log Data", - remote = false, syntax = "log:loggerName", producerOnly = true, category = { Category.CORE, Category.MONITORING }) + remote = false, internal = true, syntax = "log:loggerName", producerOnly = true, + category = { Category.CORE, Category.MONITORING }) public class LogEndpoint extends ProcessorEndpoint implements LineNumberAware { private volatile Processor logger; diff --git a/components/camel-metrics/src/generated/resources/META-INF/org/apache/camel/component/metrics/metrics.json b/components/camel-metrics/src/generated/resources/META-INF/org/apache/camel/component/metrics/metrics.json index 6927e608305f..952ca0a8b5d9 100644 --- a/components/camel-metrics/src/generated/resources/META-INF/org/apache/camel/component/metrics/metrics.json +++ b/components/camel-metrics/src/generated/resources/META-INF/org/apache/camel/component/metrics/metrics.json @@ -21,7 +21,8 @@ "producerOnly": true, "lenientProperties": false, "browsable": false, - "remote": false + "remote": false, + "internal": true }, "componentProperties": { "lazyStartProducer": { "index": 0, "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 [...] diff --git a/components/camel-metrics/src/main/java/org/apache/camel/component/metrics/MetricsEndpoint.java b/components/camel-metrics/src/main/java/org/apache/camel/component/metrics/MetricsEndpoint.java index baef89738240..d8987cf49d47 100644 --- a/components/camel-metrics/src/main/java/org/apache/camel/component/metrics/MetricsEndpoint.java +++ b/components/camel-metrics/src/main/java/org/apache/camel/component/metrics/MetricsEndpoint.java @@ -33,7 +33,8 @@ import org.apache.camel.support.DefaultEndpoint; * Collect various metrics directly from Camel routes using the DropWizard metrics library. */ @UriEndpoint(firstVersion = "2.14.0", scheme = "metrics", title = "Metrics", syntax = "metrics:metricsType:metricsName", - remote = false, producerOnly = true, category = { Category.MONITORING }, headersClass = MetricsConstants.class) + remote = false, internal = true, producerOnly = true, category = { Category.MONITORING }, + headersClass = MetricsConstants.class) public class MetricsEndpoint extends DefaultEndpoint { protected final MetricRegistry registry; diff --git a/components/camel-mock/src/generated/resources/META-INF/org/apache/camel/component/mock/mock.json b/components/camel-mock/src/generated/resources/META-INF/org/apache/camel/component/mock/mock.json index f22d774f197c..d8a7f8807de2 100644 --- a/components/camel-mock/src/generated/resources/META-INF/org/apache/camel/component/mock/mock.json +++ b/components/camel-mock/src/generated/resources/META-INF/org/apache/camel/component/mock/mock.json @@ -21,7 +21,8 @@ "producerOnly": true, "lenientProperties": true, "browsable": true, - "remote": false + "remote": false, + "internal": true }, "componentProperties": { "lazyStartProducer": { "index": 0, "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 [...] diff --git a/components/camel-mock/src/main/java/org/apache/camel/component/mock/MockEndpoint.java b/components/camel-mock/src/main/java/org/apache/camel/component/mock/MockEndpoint.java index 187c6317a126..6ac3b02ca1e5 100644 --- a/components/camel-mock/src/main/java/org/apache/camel/component/mock/MockEndpoint.java +++ b/components/camel-mock/src/main/java/org/apache/camel/component/mock/MockEndpoint.java @@ -96,7 +96,7 @@ import org.slf4j.LoggerFactory; * overrides the number of expected messages based on the number of values provided in the bodies/headers. */ @UriEndpoint(firstVersion = "1.0.0", scheme = "mock", title = "Mock", syntax = "mock:name", producerOnly = true, - remote = false, category = { Category.CORE, Category.TESTING }, lenientProperties = true) + remote = false, internal = true, category = { Category.CORE, Category.TESTING }, lenientProperties = true) public class MockEndpoint extends DefaultEndpoint implements BrowsableEndpoint, NotifyBuilderMatcher { private static final Logger LOG = LoggerFactory.getLogger(MockEndpoint.class); diff --git a/components/camel-seda/src/generated/resources/META-INF/org/apache/camel/component/seda/seda.json b/components/camel-seda/src/generated/resources/META-INF/org/apache/camel/component/seda/seda.json index 6681f3cbd6c3..0a1a4bb65b6d 100644 --- a/components/camel-seda/src/generated/resources/META-INF/org/apache/camel/component/seda/seda.json +++ b/components/camel-seda/src/generated/resources/META-INF/org/apache/camel/component/seda/seda.json @@ -21,7 +21,8 @@ "producerOnly": false, "lenientProperties": false, "browsable": true, - "remote": false + "remote": false, + "internal": 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 like [...] diff --git a/components/camel-seda/src/main/java/org/apache/camel/component/seda/SedaEndpoint.java b/components/camel-seda/src/main/java/org/apache/camel/component/seda/SedaEndpoint.java index 6ce9d7ec6510..0da80bde3d08 100644 --- a/components/camel-seda/src/main/java/org/apache/camel/component/seda/SedaEndpoint.java +++ b/components/camel-seda/src/main/java/org/apache/camel/component/seda/SedaEndpoint.java @@ -58,7 +58,7 @@ import org.slf4j.LoggerFactory; */ @ManagedResource(description = "Managed SedaEndpoint") @UriEndpoint(firstVersion = "1.1.0", scheme = "seda", title = "SEDA", syntax = "seda:name", - remote = false, category = { Category.CORE, Category.MESSAGING }) + remote = false, internal = true, category = { Category.CORE, Category.MESSAGING }) public class SedaEndpoint extends DefaultEndpoint implements AsyncEndpoint, BrowsableEndpoint, MultipleConsumersSupport { private static final Logger LOG = LoggerFactory.getLogger(SedaEndpoint.class); diff --git a/components/camel-stub/src/generated/resources/META-INF/org/apache/camel/component/stub/stub.json b/components/camel-stub/src/generated/resources/META-INF/org/apache/camel/component/stub/stub.json index 32d642f6acce..43c75bea1a28 100644 --- a/components/camel-stub/src/generated/resources/META-INF/org/apache/camel/component/stub/stub.json +++ b/components/camel-stub/src/generated/resources/META-INF/org/apache/camel/component/stub/stub.json @@ -21,7 +21,8 @@ "producerOnly": false, "lenientProperties": true, "browsable": true, - "remote": false + "remote": false, + "internal": 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 like [...] diff --git a/components/camel-stub/src/main/java/org/apache/camel/component/stub/StubEndpoint.java b/components/camel-stub/src/main/java/org/apache/camel/component/stub/StubEndpoint.java index 9265d549e7eb..e745e04d14ba 100644 --- a/components/camel-stub/src/main/java/org/apache/camel/component/stub/StubEndpoint.java +++ b/components/camel-stub/src/main/java/org/apache/camel/component/stub/StubEndpoint.java @@ -37,7 +37,7 @@ import org.apache.camel.spi.UriEndpoint; * parameters to let you quickly stub out one or more endpoints in your route temporarily. */ @UriEndpoint(firstVersion = "2.10.0", scheme = "stub", title = "Stub", syntax = "stub:name", - remote = false, category = { Category.CORE, Category.TESTING }, lenientProperties = true) + remote = false, internal = true, category = { Category.CORE, Category.TESTING }, lenientProperties = true) public class StubEndpoint extends SedaEndpoint { public StubEndpoint(String endpointUri, Component component, BlockingQueue<Exchange> queue) { diff --git a/components/camel-timer/src/generated/resources/META-INF/org/apache/camel/component/timer/timer.json b/components/camel-timer/src/generated/resources/META-INF/org/apache/camel/component/timer/timer.json index 28e78be1017b..88a27c1c699a 100644 --- a/components/camel-timer/src/generated/resources/META-INF/org/apache/camel/component/timer/timer.json +++ b/components/camel-timer/src/generated/resources/META-INF/org/apache/camel/component/timer/timer.json @@ -21,7 +21,8 @@ "producerOnly": false, "lenientProperties": false, "browsable": false, - "remote": false + "remote": false, + "internal": 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 like [...] diff --git a/components/camel-timer/src/main/java/org/apache/camel/component/timer/TimerEndpoint.java b/components/camel-timer/src/main/java/org/apache/camel/component/timer/TimerEndpoint.java index e6a80deaa9ca..943e98c3783b 100644 --- a/components/camel-timer/src/main/java/org/apache/camel/component/timer/TimerEndpoint.java +++ b/components/camel-timer/src/main/java/org/apache/camel/component/timer/TimerEndpoint.java @@ -42,7 +42,8 @@ import org.apache.camel.support.DefaultEndpoint; */ @ManagedResource(description = "Managed TimerEndpoint") @UriEndpoint(firstVersion = "1.0.0", scheme = "timer", title = "Timer", syntax = "timer:timerName", consumerOnly = true, - remote = false, category = { Category.CORE, Category.SCHEDULING }, headersClass = TimerConstants.class) + remote = false, internal = true, category = { Category.CORE, Category.SCHEDULING }, + headersClass = TimerConstants.class) public class TimerEndpoint extends DefaultEndpoint implements MultipleConsumersSupport { @UriPath @Metadata(required = true) diff --git a/core/camel-api/src/generated/java/org/apache/camel/spi/UriEndpoint.java b/core/camel-api/src/generated/java/org/apache/camel/spi/UriEndpoint.java index 048bd736794a..fc1c94f5ab92 100644 --- a/core/camel-api/src/generated/java/org/apache/camel/spi/UriEndpoint.java +++ b/core/camel-api/src/generated/java/org/apache/camel/spi/UriEndpoint.java @@ -201,6 +201,28 @@ public @interface UriEndpoint { /** * Whether the component does remote communication such as connecting to an external system over the network. Set * this to false for internal components such as log, message transformations and other kinds. + * <p/> + * Not remote does not mean that the component stays inside the CamelContext: a component that runs code, or reads a + * file or a template, is not remote either. See {@link #internal()}. */ boolean remote() default true; + + /** + * Whether the component stays inside the CamelContext: it only reaches the routes, the in-memory state (a queue, a + * cache, metrics) and the log of the CamelContext. It never reads or writes a file, uses the network, runs a + * process, or runs code or loads a resource named in its URI. A message it hands to a route (direct, seda) still + * does whatever that route does. + * <p/> + * This is about what the component can do, not what it is usually used for: a capability counts even when it sits + * behind an option that is off by default and seldom used, or in a feature that ships with the component. So + * dataset-test is not internal (it polls the endpoint named in its URI), nor is once (it can read its body from a + * file), nor micrometer (it evaluates its options with the simple language, which can load its text from a file or + * a URL). + * <p/> + * An internal component is not remote, so it sets {@code remote = false} too. Tooling uses this to tell what stays + * inside the integration, for example to send a test message to log or direct without asking the user first. + * + * @since 4.24 + */ + boolean internal() default false; } diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang-tui-ai.adoc b/docs/user-manual/modules/ROOT/pages/camel-jbang-tui-ai.adoc index 4ded91aaf6ff..2c655fbcae57 100644 --- a/docs/user-manual/modules/ROOT/pages/camel-jbang-tui-ai.adoc +++ b/docs/user-manual/modules/ROOT/pages/camel-jbang-tui-ai.adoc @@ -196,8 +196,10 @@ code ask you first, in a dialog that shows the call: * writing a file: the diff dialog, or the live replay in the Source editor (see `/write` above); * sending a message to an endpoint the integration does not have, such as a file, a command, an HTTP service or - another topic; a message to a route, to an internal endpoint (`direct:`, `seda:`, `log:`, `mock:`, `stub:` - and the like), or to an endpoint the integration uses goes ahead; + another topic; a message to a route, to an endpoint the integration uses, or to an internal endpoint goes ahead. + Internal is what the Camel catalog marks so: a component that stays inside the integration (`direct:`, `seda:`, + `log:`, `mock:`, `stub:` and the like), with no option or feature that reaches a file or the network, even one + seldom used; * SQL other than a single `SELECT`, `SHOW` or `DESCRIBE`, and updating a row; * evaluating an expression in a language that runs code, such as Groovy, Java, JavaScript or Python. diff --git a/docs/user-manual/modules/ROOT/pages/security-model.adoc b/docs/user-manual/modules/ROOT/pages/security-model.adoc index 712c68e3ad85..b192438fe12b 100644 --- a/docs/user-manual/modules/ROOT/pages/security-model.adoc +++ b/docs/user-manual/modules/ROOT/pages/security-model.adoc @@ -152,8 +152,9 @@ deliberately few, and they are the contract: unless the developer chose `/write auto`. * The developer confirms a call that reaches beyond the integration, may destroy data or runs code: a message to an endpoint the integration does not - have (a route, an internal endpoint such as `direct:`, `seda:` or `log:`, - and the integration's own endpoints are inside it), a SQL statement other + have (a route, an endpoint of a component the Camel catalog marks internal, + such as `direct:`, `seda:` or `log:`, and the integration's own endpoints are + inside it), a SQL statement other than a single `SELECT`, `SHOW` or `DESCRIBE`, a row update, and an expression in a language that runs code, such as Groovy. An HTTP request goes only to the integration's own server on `localhost`. diff --git a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ToolConfirms.java b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ToolConfirms.java index 876235757f41..56b1bfdc1747 100644 --- a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ToolConfirms.java +++ b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ToolConfirms.java @@ -23,6 +23,9 @@ import java.util.Collection; import java.util.Locale; import java.util.Set; +import org.apache.camel.catalog.CamelCatalog; +import org.apache.camel.catalog.DefaultCamelCatalog; +import org.apache.camel.tooling.model.ComponentModel; import org.apache.camel.util.URISupport; /** @@ -30,8 +33,8 @@ import org.apache.camel.util.URISupport; * agent and an MCP client run its tools without asking, so the AI can show and tell at once (see "Developer tools" in * the security model). The exceptions are the calls that reach beyond the integration, may destroy data or run code: * <ul> - * <li>tui_send_message to an endpoint the integration does not have; a route id, a pattern and an internal endpoint - * (direct:, seda:, log:, mock: and the like) stay inside it;</li> + * <li>tui_send_message to an endpoint the integration does not have; a route id, a pattern and an endpoint of a + * component the catalog marks internal (direct:, seda:, log:, mock: and the like) stay inside it;</li> * <li>tui_execute_sql with a statement that is not a single SELECT (or SHOW, DESCRIBE), and tui_update_row;</li> * <li>camel_eval_expression in a language that runs code, such as Groovy.</li> * </ul> @@ -48,15 +51,31 @@ final class ToolConfirms { static final Set<String> CODE_LANGUAGES = Set.of("groovy", "java", "joor", "js", "javascript", "python", "mvel", "ognl", "spel"); + private ToolConfirms() { + } + /** - * The components that stay inside the integration: its routes and in-memory queues, its log and the test endpoints. - * Not every component the catalog marks remote=false: exec, class, bean, language and the components that load a - * template or a stylesheet by URI are not remote either, but run code, or read a file or a URL. + * Whether a component stays inside the integration, as the catalog marks it internal: its routes, in-memory state + * and log, and no file, network, process, or code or resource named in its URI, by any option. This is narrower + * than remote=false, which exec, class, bean, language and the components that load a template or a stylesheet by + * URI are too. The catalog is the TUI's own, so it has the flag; a component it does not know (a custom one, or one + * newer than the TUI) is not internal. */ - static final Set<String> INTERNAL_SCHEMES = Set.of( - "direct", "seda", "disruptor", "disruptor-vm", "log", "mock", "stub", "browse", "dataset", "dataset-test"); + static boolean isInternal(String scheme) { + if (!scheme.matches("[a-z0-9-]+")) { + return false; + } + try { + ComponentModel model = Catalog.INSTANCE.componentModel(scheme); + return model != null && model.isInternal(); + } catch (RuntimeException e) { + return false; + } + } - private ToolConfirms() { + // loaded on the first send, not when a call only needs the SQL or language checks + private static final class Catalog { + static final CamelCatalog INSTANCE = new DefaultCamelCatalog(true); } /** A message to an endpoint the integration does not have, or null when it stays inside the integration. */ @@ -81,7 +100,7 @@ final class ToolConfirms { // an option can still reach out: #class:...(args) runs any constructor (a FileOutputStream truncates a file), // and a {{placeholder}} can put a secret in the log String decoded = decode(endpoint); - if (INTERNAL_SCHEMES.contains(endpoint.substring(0, endpoint.indexOf(':'))) + if (isInternal(endpoint.substring(0, endpoint.indexOf(':'))) && !decoded.contains("#") && !decoded.contains("{{")) { return true; } diff --git a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/ToolConfirmsTest.java b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/ToolConfirmsTest.java index f1b64d82e52f..97707a0e8496 100644 --- a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/ToolConfirmsTest.java +++ b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/ToolConfirmsTest.java @@ -39,12 +39,14 @@ class ToolConfirmsTest { // a route id or a pattern: the send console picks one of the integration's routes assertThat(ToolConfirms.sendMessage("checkout", ENDPOINTS)).isNull(); assertThat(ToolConfirms.sendMessage("kafka:*", ENDPOINTS)).isNull(); - // an internal endpoint stays inside the integration: its routes, its log, the test endpoints + // an endpoint of a component the catalog marks internal stays inside the integration: its routes, in-memory + // state, log and test endpoints assertThat(ToolConfirms.sendMessage("direct:unknown", ENDPOINTS)).isNull(); assertThat(ToolConfirms.sendMessage("seda:work", List.of())).isNull(); assertThat(ToolConfirms.sendMessage("log:demo?showAll=true", List.of())).isNull(); assertThat(ToolConfirms.sendMessage("mock:result", List.of())).isNull(); assertThat(ToolConfirms.sendMessage("stub:kafka:payments", List.of())).isNull(); + assertThat(ToolConfirms.sendMessage("caffeine-cache:orders?action=PUT&key=1", List.of())).isNull(); } @Test @@ -75,6 +77,15 @@ class ToolConfirmsTest { assertThat(ToolConfirms.sendMessage("class:java.lang.Runtime", List.of())).isNotNull(); assertThat(ToolConfirms.sendMessage("language:groovy:'touch /tmp/x'.execute()", List.of())).isNotNull(); assertThat(ToolConfirms.sendMessage("velocity:file:/Users/me/.ssh/id_rsa", List.of())).isNotNull(); + // they look internal but are not, as a seldom used option or feature reaches out: dataset-test polls the + // endpoint in its URI (a file consumer moves the files it reads), micrometer evaluates its options with simple, + // which loads a resource: text from a file or a URL + assertThat(ToolConfirms.sendMessage("dataset-test:file:/Users/me/work", List.of())).isNotNull(); + assertThat(ToolConfirms.sendMessage("micrometer:counter:resource:file:/Users/me/.aws/credentials", List.of())) + .isNotNull(); + // a component the catalog does not know, such as a custom one + assertThat(ToolConfirms.sendMessage("acme:orders", List.of())).isNotNull(); + assertThat(ToolConfirms.isInternal("../components/log")).isFalse(); } @Test diff --git a/tooling/camel-tooling-model/src/main/java/org/apache/camel/tooling/model/ComponentModel.java b/tooling/camel-tooling-model/src/main/java/org/apache/camel/tooling/model/ComponentModel.java index 561849cf3906..bfce0ec3818b 100644 --- a/tooling/camel-tooling-model/src/main/java/org/apache/camel/tooling/model/ComponentModel.java +++ b/tooling/camel-tooling-model/src/main/java/org/apache/camel/tooling/model/ComponentModel.java @@ -37,6 +37,7 @@ public class ComponentModel extends ArtifactModel<ComponentModel.ComponentOption protected boolean lenientProperties; protected boolean browsable; protected boolean remote; + protected boolean internal; protected String verifiers; protected final List<EndpointOptionModel> endpointOptions = new ArrayList<>(); protected final List<EndpointHeaderModel> headers = new ArrayList<>(); @@ -155,6 +156,18 @@ public class ComponentModel extends ArtifactModel<ComponentModel.ComponentOption this.remote = remote; } + /** + * Whether the component stays inside the CamelContext: no file, network, process, or code or resource named in its + * URI, by any option or feature (see {@code UriEndpoint.internal()}). + */ + public boolean isInternal() { + return internal; + } + + public void setInternal(boolean internal) { + this.internal = internal; + } + public String getVerifiers() { return verifiers; } 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 8921f15869fc..3e8474dea729 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 @@ -205,6 +205,7 @@ public final class JsonMapper { model.setLenientProperties(mobj.getBooleanOrDefault("lenientProperties", false)); model.setBrowsable(mobj.getBooleanOrDefault("browsable", false)); model.setRemote(mobj.getBooleanOrDefault("remote", false)); + model.setInternal(mobj.getBooleanOrDefault("internal", false)); parseArtifact(mobj, model); } @@ -238,6 +239,10 @@ public final class JsonMapper { obj.put("lenientProperties", model.isLenientProperties()); obj.put("browsable", model.isBrowsable()); obj.put("remote", model.isRemote()); + // only written for the few internal components; a catalog without it reads as not internal + if (model.isInternal()) { + obj.put("internal", true); + } obj.put("verifiers", model.getVerifiers()); obj.entrySet().removeIf(e -> e.getValue() == null); JsonObject wrapper = new JsonObject(); diff --git a/tooling/camel-tooling-model/src/test/java/org/apache/camel/tooling/model/JsonMapperTest.java b/tooling/camel-tooling-model/src/test/java/org/apache/camel/tooling/model/JsonMapperTest.java index 18c4d56cc2ab..8112520b1d6a 100644 --- a/tooling/camel-tooling-model/src/test/java/org/apache/camel/tooling/model/JsonMapperTest.java +++ b/tooling/camel-tooling-model/src/test/java/org/apache/camel/tooling/model/JsonMapperTest.java @@ -39,6 +39,19 @@ class JsonMapperTest { assertTrue(model2.getEndpointHeaders().isEmpty()); } + @Test + void testShouldWriteInternalOnlyWhenSet() { + ComponentModel model = new ComponentModel(); + String json = JsonMapper.createParameterJsonSchema(model); + assertFalse(json.contains("\"internal\"")); + assertFalse(JsonMapper.generateComponentModel(json).isInternal()); + + model.setInternal(true); + json = JsonMapper.createParameterJsonSchema(model); + assertTrue(json.contains("\"internal\": true")); + assertTrue(JsonMapper.generateComponentModel(json).isInternal()); + } + @Test void testShouldSerializeAndDeserializeComponentWithOneHeader() { ComponentModel model = new ComponentModel(); 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 919af18c16a0..5c0db7ec11a5 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 @@ -824,6 +824,11 @@ public class EndpointSchemaGeneratorMojo extends AbstractGeneratorMojo { UriEndpoint uriEndpoint, Class<?> endpointClassElement, String title, String scheme, String extendsScheme, String label, String[] schemes) throws MojoExecutionException { + if (uriEndpoint.internal() && uriEndpoint.remote()) { + throw new MojoExecutionException( + "@UriEndpoint(internal = true) on " + endpointClassElement.getName() + + " needs remote = false too: an internal component does not reach the network"); + } ComponentModel model = new ComponentModel(); model.setScheme(scheme); model.setName(scheme); @@ -847,6 +852,7 @@ public class EndpointSchemaGeneratorMojo extends AbstractGeneratorMojo { model.setProducerOnly(uriEndpoint.producerOnly()); model.setLenientProperties(uriEndpoint.lenientProperties()); model.setRemote(uriEndpoint.remote()); + model.setInternal(uriEndpoint.internal()); model.setAsync(loadClass("org.apache.camel.AsyncEndpoint").isAssignableFrom(endpointClassElement)); model.setApi(loadClass("org.apache.camel.ApiEndpoint").isAssignableFrom(endpointClassElement)); model.setBrowsable(loadClass("org.apache.camel.spi.BrowsableEndpoint").isAssignableFrom(endpointClassElement)); diff --git a/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/EndpointSchemaGeneratorMojoTest.java b/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/EndpointSchemaGeneratorMojoTest.java index b717f0343e00..562fce01273e 100644 --- a/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/EndpointSchemaGeneratorMojoTest.java +++ b/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/EndpointSchemaGeneratorMojoTest.java @@ -31,9 +31,11 @@ import org.apache.camel.maven.packaging.endpoint.SomeEndpointWithHeaderInterface import org.apache.camel.maven.packaging.endpoint.SomeEndpointWithJavadocAsDescription; import org.apache.camel.maven.packaging.endpoint.SomeEndpointWithoutHeaders; import org.apache.camel.maven.packaging.endpoint.SomeExtendingEndpoint; +import org.apache.camel.maven.packaging.endpoint.SomeInternalRemoteEndpoint; import org.apache.camel.spi.UriEndpoint; import org.apache.camel.tooling.model.ComponentModel; import org.apache.camel.tooling.model.ComponentModel.EndpointHeaderModel; +import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.project.MavenProject; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -44,6 +46,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; /** @@ -131,6 +134,15 @@ class EndpointSchemaGeneratorMojoTest { assertEquals(0, model.getEndpointHeaders().size()); } + @Test + void testInternalEndpointMustNotBeRemote() { + UriEndpoint endpoint = SomeInternalRemoteEndpoint.class.getAnnotation(UriEndpoint.class); + MojoExecutionException e = assertThrows(MojoExecutionException.class, + () -> mojo.findComponentProperties(endpoint, SomeInternalRemoteEndpoint.class, "some", "some", null, null, + null)); + assertTrue(e.getMessage().contains("needs remote = false"), e.getMessage()); + } + @Test void testEndpointWithoutHeadersAreIgnored() { mojo.addEndpointHeaders(model, SomeEndpointWithoutHeaders.class.getAnnotation(UriEndpoint.class), "some"); diff --git a/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/endpoint/SomeInternalRemoteEndpoint.java b/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/endpoint/SomeInternalRemoteEndpoint.java new file mode 100644 index 000000000000..83b90a7e5b0c --- /dev/null +++ b/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/endpoint/SomeInternalRemoteEndpoint.java @@ -0,0 +1,24 @@ +/* + * 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.endpoint; + +import org.apache.camel.spi.UriEndpoint; + +// internal without remote = false, which the generator refuses +@UriEndpoint(scheme = "some", syntax = "some", title = "some", internal = true) +public class SomeInternalRemoteEndpoint { +} diff --git a/tooling/spi-annotations/src/main/java/org/apache/camel/spi/UriEndpoint.java b/tooling/spi-annotations/src/main/java/org/apache/camel/spi/UriEndpoint.java index 048bd736794a..fc1c94f5ab92 100644 --- a/tooling/spi-annotations/src/main/java/org/apache/camel/spi/UriEndpoint.java +++ b/tooling/spi-annotations/src/main/java/org/apache/camel/spi/UriEndpoint.java @@ -201,6 +201,28 @@ public @interface UriEndpoint { /** * Whether the component does remote communication such as connecting to an external system over the network. Set * this to false for internal components such as log, message transformations and other kinds. + * <p/> + * Not remote does not mean that the component stays inside the CamelContext: a component that runs code, or reads a + * file or a template, is not remote either. See {@link #internal()}. */ boolean remote() default true; + + /** + * Whether the component stays inside the CamelContext: it only reaches the routes, the in-memory state (a queue, a + * cache, metrics) and the log of the CamelContext. It never reads or writes a file, uses the network, runs a + * process, or runs code or loads a resource named in its URI. A message it hands to a route (direct, seda) still + * does whatever that route does. + * <p/> + * This is about what the component can do, not what it is usually used for: a capability counts even when it sits + * behind an option that is off by default and seldom used, or in a feature that ships with the component. So + * dataset-test is not internal (it polls the endpoint named in its URI), nor is once (it can read its body from a + * file), nor micrometer (it evaluates its options with the simple language, which can load its text from a file or + * a URL). + * <p/> + * An internal component is not remote, so it sets {@code remote = false} too. Tooling uses this to tell what stays + * inside the integration, for example to send a test message to log or direct without asking the user first. + * + * @since 4.24 + */ + boolean internal() default false; }
