This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 2968c79e751c CAMEL-24658: camel-catalog - find components by protocol
or product name (s3 -> aws2-s3, mqtt -> paho-mqtt5) (#26215)
2968c79e751c is described below
commit 2968c79e751c465fb947e8b4a79d42dd1cd2e9d5
Author: Claus Ibsen <[email protected]>
AuthorDate: Tue Sep 8 22:06:56 2026 +0200
CAMEL-24658: camel-catalog - find components by protocol or product name
(s3 -> aws2-s3, mqtt -> paho-mqtt5) (#26215)
Adds suggestComponentNames, suggestDataFormatNames and suggestLanguageNames
to CamelCatalog. They rank matches by exact scheme, declared aliases,
alternative schemes, title words, scheme words and finally substring, and
return a component that shares one implementation under several schemes
(imap, pop3, smtp) only once. The lookup is a default method working on
the existing JSON, so it also serves older catalogs loaded via
CatalogLoader.
Component aliases reuse @Metadata(aliases) on the endpoint class, which the
endpoint schema generator now copies into the component model. The mail
component declares mail/email and ActiveMQ declares amq.
The Camel TUI drops its hardcoded scheme alias map in favour of the catalog
and tui_catalog_doc returns suggestions when a name is not found. The
camel catalog commands include the suggestions in their did-you-mean output.
Closes #26215
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Signed-off-by: Claus Ibsen <[email protected]>
---
.../apache/camel/catalog/components/activemq.json | 1 +
.../apache/camel/catalog/components/activemq6.json | 1 +
.../org/apache/camel/catalog/components/imap.json | 1 +
.../org/apache/camel/catalog/components/imaps.json | 1 +
.../org/apache/camel/catalog/components/pop3.json | 1 +
.../org/apache/camel/catalog/components/pop3s.json | 1 +
.../org/apache/camel/catalog/components/smtp.json | 1 +
.../org/apache/camel/catalog/components/smtps.json | 1 +
.../org/apache/camel/catalog/CamelCatalog.java | 45 +++++
.../apache/camel/catalog/CatalogTermMatcher.java | 199 +++++++++++++++++++++
.../org/apache/camel/catalog/CamelCatalogTest.java | 59 ++++++
.../apache/camel/component/activemq/activemq.json | 1 +
.../camel/component/activemq/ActiveMQEndpoint.java | 2 +
.../camel/component/activemq6/activemq6.json | 1 +
.../component/activemq6/ActiveMQEndpoint.java | 2 +
.../org/apache/camel/component/mail/imap.json | 1 +
.../org/apache/camel/component/mail/imaps.json | 1 +
.../org/apache/camel/component/mail/pop3.json | 1 +
.../org/apache/camel/component/mail/pop3s.json | 1 +
.../org/apache/camel/component/mail/smtp.json | 1 +
.../org/apache/camel/component/mail/smtps.json | 1 +
.../apache/camel/component/mail/MailEndpoint.java | 2 +
.../modules/ROOT/pages/camel-catalog.adoc | 34 ++++
.../core/commands/catalog/CatalogBaseCommand.java | 14 +-
.../core/commands/catalog/CatalogComponent.java | 5 +
.../core/commands/catalog/CatalogDataFormat.java | 5 +
.../core/commands/catalog/CatalogLanguage.java | 5 +
.../commands/catalog/CatalogComponentTest.java | 11 ++
.../jbang/core/commands/tui/TuiToolRegistry.java | 69 +++----
.../tui/TuiToolRegistrySuggestComponentsTest.java | 46 -----
.../packaging/EndpointSchemaGeneratorMojo.java | 6 +
31 files changed, 429 insertions(+), 91 deletions(-)
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/activemq.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/activemq.json
index a09d44a724dd..d6d6c9c9d608 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/activemq.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/activemq.json
@@ -9,6 +9,7 @@
"label": "messaging",
"javaType": "org.apache.camel.component.activemq.ActiveMQComponent",
"supportLevel": "Stable",
+ "aliases": [ "amq" ],
"groupId": "org.apache.camel",
"artifactId": "camel-activemq",
"version": "4.23.0-SNAPSHOT",
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/activemq6.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/activemq6.json
index 04ddf3b3a40b..b1e04a0ba8b4 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/activemq6.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/activemq6.json
@@ -9,6 +9,7 @@
"label": "messaging",
"javaType": "org.apache.camel.component.activemq6.ActiveMQComponent",
"supportLevel": "Stable",
+ "aliases": [ "amq" ],
"groupId": "org.apache.camel",
"artifactId": "camel-activemq6",
"version": "4.23.0-SNAPSHOT",
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/imap.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/imap.json
index 6c49e15393b5..621ba167453a 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/imap.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/imap.json
@@ -9,6 +9,7 @@
"label": "mail",
"javaType": "org.apache.camel.component.mail.MailComponent",
"supportLevel": "Stable",
+ "aliases": [ "mail", "email" ],
"groupId": "org.apache.camel",
"artifactId": "camel-mail",
"version": "4.23.0-SNAPSHOT",
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/imaps.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/imaps.json
index 2d59fa225fa5..be87ed8c11ae 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/imaps.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/imaps.json
@@ -9,6 +9,7 @@
"label": "mail",
"javaType": "org.apache.camel.component.mail.MailComponent",
"supportLevel": "Stable",
+ "aliases": [ "mail", "email" ],
"groupId": "org.apache.camel",
"artifactId": "camel-mail",
"version": "4.23.0-SNAPSHOT",
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pop3.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pop3.json
index 6827a27d73bf..e868fcf6abdd 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pop3.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pop3.json
@@ -9,6 +9,7 @@
"label": "mail",
"javaType": "org.apache.camel.component.mail.MailComponent",
"supportLevel": "Stable",
+ "aliases": [ "mail", "email" ],
"groupId": "org.apache.camel",
"artifactId": "camel-mail",
"version": "4.23.0-SNAPSHOT",
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pop3s.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pop3s.json
index 582c2818dc8a..d2e95187a967 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pop3s.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pop3s.json
@@ -9,6 +9,7 @@
"label": "mail",
"javaType": "org.apache.camel.component.mail.MailComponent",
"supportLevel": "Stable",
+ "aliases": [ "mail", "email" ],
"groupId": "org.apache.camel",
"artifactId": "camel-mail",
"version": "4.23.0-SNAPSHOT",
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/smtp.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/smtp.json
index c0cd0d423a4e..33dff5f867f5 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/smtp.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/smtp.json
@@ -9,6 +9,7 @@
"label": "mail",
"javaType": "org.apache.camel.component.mail.MailComponent",
"supportLevel": "Stable",
+ "aliases": [ "mail", "email" ],
"groupId": "org.apache.camel",
"artifactId": "camel-mail",
"version": "4.23.0-SNAPSHOT",
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/smtps.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/smtps.json
index c5c1721f6c6a..2b2188d35521 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/smtps.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/smtps.json
@@ -9,6 +9,7 @@
"label": "mail",
"javaType": "org.apache.camel.component.mail.MailComponent",
"supportLevel": "Stable",
+ "aliases": [ "mail", "email" ],
"groupId": "org.apache.camel",
"artifactId": "camel-mail",
"version": "4.23.0-SNAPSHOT",
diff --git
a/catalog/camel-catalog/src/main/java/org/apache/camel/catalog/CamelCatalog.java
b/catalog/camel-catalog/src/main/java/org/apache/camel/catalog/CamelCatalog.java
index d71a426840bc..c0ba6aa5638f 100644
---
a/catalog/camel-catalog/src/main/java/org/apache/camel/catalog/CamelCatalog.java
+++
b/catalog/camel-catalog/src/main/java/org/apache/camel/catalog/CamelCatalog.java
@@ -266,6 +266,51 @@ public interface CamelCatalog {
*/
List<String> findOtherNames(String filter);
+ /**
+ * Finds component names that match a term such as a protocol or product
name, best match first: the exact scheme,
+ * then declared aliases, alternative schemes, words of the title, words
of the scheme, and finally schemes
+ * containing the term. Components that share one implementation under
several schemes (such as imap, pop3 and smtp)
+ * are returned once, by the scheme that matched or otherwise their
primary scheme.
+ * <p>
+ * For example <tt>mqtt</tt> finds <tt>paho-mqtt5</tt>, <tt>s3</tt> finds
<tt>aws2-s3</tt>, and <tt>amq</tt> finds
+ * <tt>activemq</tt>.
+ *
+ * @param term the protocol, product, or component name to look for
+ * @param max the maximum number of names to return, or 0 for no limit
+ * @return the matching component names, or an empty list if none
match
+ * @since 4.23
+ */
+ default List<String> suggestComponentNames(String term, int max) {
+ return CatalogTermMatcher.suggestComponentNames(this, term, max);
+ }
+
+ /**
+ * Finds data format names that match a term such as a format or library
name (for example <tt>yaml</tt> finds
+ * <tt>snakeYaml</tt>), best match first: the exact name, then declared
aliases, words of the title, words of the
+ * name, and finally names containing the term.
+ *
+ * @param term the format, library, or data format name to look for
+ * @param max the maximum number of names to return, or 0 for no limit
+ * @return the matching data format names, or an empty list if none
match
+ * @since 4.23
+ */
+ default List<String> suggestDataFormatNames(String term, int max) {
+ return CatalogTermMatcher.suggestNames(findDataFormatNames(),
this::dataFormatModel, term, max);
+ }
+
+ /**
+ * Finds language names that match a term, best match first: the exact
name, then declared aliases, words of the
+ * title, words of the name, and finally names containing the term.
+ *
+ * @param term the language name to look for
+ * @param max the maximum number of names to return, or 0 for no limit
+ * @return the matching language names, or an empty list if none match
+ * @since 4.23
+ */
+ default List<String> suggestLanguageNames(String term, int max) {
+ return CatalogTermMatcher.suggestNames(findLanguageNames(),
this::languageModel, term, max);
+ }
+
/**
* Returns the component information as JSON format.
*
diff --git
a/catalog/camel-catalog/src/main/java/org/apache/camel/catalog/CatalogTermMatcher.java
b/catalog/camel-catalog/src/main/java/org/apache/camel/catalog/CatalogTermMatcher.java
new file mode 100644
index 000000000000..70093f5e1fa9
--- /dev/null
+++
b/catalog/camel-catalog/src/main/java/org/apache/camel/catalog/CatalogTermMatcher.java
@@ -0,0 +1,199 @@
+/*
+ * 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.catalog;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.function.Function;
+
+import org.apache.camel.tooling.model.BaseModel;
+import org.apache.camel.tooling.model.ComponentModel;
+
+/**
+ * Ranks catalog entries against a search term such as a protocol or product
name (mqtt, s3, rabbitmq) for the suggest
+ * methods on {@link CamelCatalog}.
+ */
+final class CatalogTermMatcher {
+
+ private static final int NO_MATCH = -1;
+ /** Shorter terms are too ambiguous to match as a substring of a name. */
+ private static final int MIN_SUBSTRING_LENGTH = 3;
+
+ private record Match(String name, int rank, String group) {
+ }
+
+ private CatalogTermMatcher() {
+ }
+
+ /**
+ * Component names matching the term, best match first. Components that
share one implementation under several
+ * schemes (imap, pop3, smtp) are returned once: by the scheme that
matched, or otherwise their primary scheme.
+ */
+ static List<String> suggestComponentNames(CamelCatalog catalog, String
term, int max) {
+ String key = normalize(term);
+ if (key.isEmpty()) {
+ return List.of();
+ }
+ List<Match> matches = new ArrayList<>();
+ for (String name : catalog.findComponentNames()) {
+ ComponentModel model = name == null || name.isBlank() ? null :
catalog.componentModel(name);
+ if (model == null) {
+ continue;
+ }
+ int rank = rankComponent(model, key);
+ if (rank != NO_MATCH) {
+ String group = model.getAlternativeSchemes();
+ matches.add(new Match(name, rank, group == null ||
group.isBlank() ? null : group));
+ }
+ }
+ Map<String, Match> bestPerGroup = new HashMap<>();
+ for (Match match : matches) {
+ if (match.group() != null) {
+ bestPerGroup.merge(match.group(), match,
CatalogTermMatcher::better);
+ }
+ }
+ matches.removeIf(m -> m.group() != null && bestPerGroup.get(m.group())
!= m);
+ return names(matches, max);
+ }
+
+ /**
+ * Data format or language names matching the term, best match first.
+ */
+ static List<String> suggestNames(
+ List<String> names, Function<String, ? extends BaseModel<?>>
modelLoader, String term, int max) {
+ String key = normalize(term);
+ if (key.isEmpty()) {
+ return List.of();
+ }
+ List<Match> matches = new ArrayList<>();
+ for (String name : names) {
+ BaseModel<?> model = name == null || name.isBlank() ? null :
modelLoader.apply(name);
+ if (model == null) {
+ continue;
+ }
+ int rank = rankNamed(model, key);
+ if (rank != NO_MATCH) {
+ matches.add(new Match(name, rank, null));
+ }
+ }
+ return names(matches, max);
+ }
+
+ private static int rankComponent(ComponentModel model, String key) {
+ String scheme = model.getScheme();
+ if (key.equals(normalize(scheme))) {
+ return 0;
+ }
+ if (matchesAlias(model, key)) {
+ return 1;
+ }
+ if (model.getAlternativeSchemes() != null &&
containsNormalized(model.getAlternativeSchemes().split(","), key)) {
+ return 2;
+ }
+ if (matchesTitle(model, key)) {
+ return 3;
+ }
+ if (containsNormalized(words(scheme), key)) {
+ return 4;
+ }
+ if (key.length() >= MIN_SUBSTRING_LENGTH &&
normalize(scheme).contains(key)) {
+ return 5;
+ }
+ return NO_MATCH;
+ }
+
+ private static int rankNamed(BaseModel<?> model, String key) {
+ String name = model.getName();
+ if (key.equals(normalize(name))) {
+ return 0;
+ }
+ if (matchesAlias(model, key)) {
+ return 1;
+ }
+ if (matchesTitle(model, key)) {
+ return 2;
+ }
+ if (containsNormalized(camelCaseWords(name), key)) {
+ return 3;
+ }
+ if (key.length() >= MIN_SUBSTRING_LENGTH &&
normalize(name).contains(key)) {
+ return 4;
+ }
+ return NO_MATCH;
+ }
+
+ private static boolean matchesAlias(BaseModel<?> model, String key) {
+ List<String> aliases = model.getAliases();
+ return aliases != null && containsNormalized(aliases.toArray(new
String[0]), key);
+ }
+
+ private static boolean matchesTitle(BaseModel<?> model, String key) {
+ String title = model.getTitle();
+ return title != null && (key.equals(normalize(title)) ||
containsNormalized(words(title), key));
+ }
+
+ private static Match better(Match a, Match b) {
+ if (a.rank() != b.rank()) {
+ return a.rank() < b.rank() ? a : b;
+ }
+ // same rank: prefer the scheme listed first, which is the primary one
+ List<String> schemes = Arrays.asList(a.group().split(","));
+ return schemes.indexOf(b.name()) < schemes.indexOf(a.name()) ? b : a;
+ }
+
+ private static List<String> names(List<Match> matches, int max) {
+ matches.sort(Comparator.comparingInt(Match::rank));
+ List<String> answer = new ArrayList<>(matches.size());
+ for (Match match : matches) {
+ if (max > 0 && answer.size() >= max) {
+ break;
+ }
+ // a catalog can list a name twice when a component was added on
top of the built-in ones
+ if (!answer.contains(match.name())) {
+ answer.add(match.name());
+ }
+ }
+ return answer;
+ }
+
+ private static boolean containsNormalized(String[] candidates, String key)
{
+ for (String candidate : candidates) {
+ if (key.equals(normalize(candidate))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static String[] words(String text) {
+ return text == null ? new String[0] : text.split("[^A-Za-z0-9]+");
+ }
+
+ private static String[] camelCaseWords(String text) {
+ return text == null ? new String[0] :
words(text.replaceAll("([a-z0-9])([A-Z])", "$1 $2"));
+ }
+
+ private static String normalize(String text) {
+ return text == null ? "" :
text.toLowerCase(Locale.ROOT).replaceAll("[^a-z0-9]", "");
+ }
+
+}
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 cc847e65b3c4..b4ea441b8927 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
@@ -182,6 +182,65 @@ public class CamelCatalogTest {
assertTrue(names.contains("saga"));
}
+ @Test
+ public void testComponentAliases() {
+ // aliases declared via @Metadata on the endpoint class end up in the
component model
+ ComponentModel mail = catalog.componentModel("imap");
+ assertNotNull(mail);
+ assertTrue(mail.getAliases().contains("mail"));
+ assertTrue(mail.getAliases().contains("email"));
+
assertTrue(catalog.componentModel("activemq").getAliases().contains("amq"));
+ }
+
+ @Test
+ public void testSuggestComponentNames() {
+ // exact scheme first, then words of the title or scheme
+ assertEquals(List.of("aws2-s3", "aws2-s3-vectors"),
catalog.suggestComponentNames("s3", 0));
+ assertEquals(List.of("aws2-sqs"), catalog.suggestComponentNames("sqs",
0));
+ assertEquals(List.of("paho-mqtt5"),
catalog.suggestComponentNames("mqtt", 0));
+ assertEquals(List.of("spring-rabbitmq"),
catalog.suggestComponentNames("rabbitmq", 0));
+ assertEquals(List.of("google-pubsub"),
catalog.suggestComponentNames("pubsub", 0));
+ assertEquals(List.of("azure-servicebus"),
catalog.suggestComponentNames("servicebus", 0));
+ assertEquals(List.of("azure-servicebus"),
catalog.suggestComponentNames("Service-Bus", 0));
+ assertEquals(List.of("kafka", "aws2-msk"),
catalog.suggestComponentNames("kafka", 0));
+ // aliases rank right after the exact scheme, substring matches last
+ assertEquals(List.of("activemq", "activemq6", "amqp"),
catalog.suggestComponentNames("amq", 0));
+ assertEquals(List.of("paho-mqtt5"),
catalog.suggestComponentNames("paho-mqtt", 0));
+ assertTrue(catalog.suggestComponentNames("xyzq", 0).isEmpty());
+ assertTrue(catalog.suggestComponentNames("", 5).isEmpty());
+ assertTrue(catalog.suggestComponentNames(null, 5).isEmpty());
+ // max caps the result
+ List<String> aws = catalog.suggestComponentNames("aws", 0);
+ assertTrue(aws.size() > 5, "aws should match many components, was: " +
aws);
+ assertEquals(aws.subList(0, 5), catalog.suggestComponentNames("aws",
5));
+ }
+
+ @Test
+ public void testSuggestComponentNamesDedupesAlternativeSchemes() {
+ // one implementation under several schemes is suggested once, by the
scheme that matched
+ assertEquals(List.of("smtp"), catalog.suggestComponentNames("smtp",
0));
+ assertEquals(List.of("https"), catalog.suggestComponentNames("https",
0));
+ // or by its primary scheme when the match came from an alias
+ List<String> mail = catalog.suggestComponentNames("mail", 0);
+ assertEquals("imap", mail.get(0), "mail should suggest the mail
component first, was: " + mail);
+ assertFalse(mail.contains("smtp"), "mail should not repeat the mail
component, was: " + mail);
+ assertTrue(mail.contains("google-mail"), "mail should also suggest
google-mail, was: " + mail);
+ }
+
+ @Test
+ public void testSuggestDataFormatAndLanguageNames() {
+ assertEquals(List.of("snakeYaml"),
catalog.suggestDataFormatNames("yaml", 0));
+ List<String> json = catalog.suggestDataFormatNames("json", 0);
+ assertTrue(json.contains("jackson"), "json should suggest jackson,
was: " + json);
+ assertTrue(json.contains("gson"), "json should suggest gson, was: " +
json);
+ assertEquals("jackson", catalog.suggestDataFormatNames("jackson",
0).get(0));
+
+ assertEquals("simple", catalog.suggestLanguageNames("simple",
0).get(0));
+ List<String> path = catalog.suggestLanguageNames("path", 0);
+ assertTrue(path.contains("xpath"), "path should suggest xpath, was: "
+ path);
+ assertTrue(path.contains("jsonpath"), "path should suggest jsonpath,
was: " + path);
+ }
+
@Test
public void testEipModelAliases() {
// verify aliases are present in the EIP model
diff --git
a/components/camel-activemq/src/generated/resources/META-INF/org/apache/camel/component/activemq/activemq.json
b/components/camel-activemq/src/generated/resources/META-INF/org/apache/camel/component/activemq/activemq.json
index a09d44a724dd..d6d6c9c9d608 100644
---
a/components/camel-activemq/src/generated/resources/META-INF/org/apache/camel/component/activemq/activemq.json
+++
b/components/camel-activemq/src/generated/resources/META-INF/org/apache/camel/component/activemq/activemq.json
@@ -9,6 +9,7 @@
"label": "messaging",
"javaType": "org.apache.camel.component.activemq.ActiveMQComponent",
"supportLevel": "Stable",
+ "aliases": [ "amq" ],
"groupId": "org.apache.camel",
"artifactId": "camel-activemq",
"version": "4.23.0-SNAPSHOT",
diff --git
a/components/camel-activemq/src/main/java/org/apache/camel/component/activemq/ActiveMQEndpoint.java
b/components/camel-activemq/src/main/java/org/apache/camel/component/activemq/ActiveMQEndpoint.java
index be92147a9dc4..c2c8432f5ff0 100644
---
a/components/camel-activemq/src/main/java/org/apache/camel/component/activemq/ActiveMQEndpoint.java
+++
b/components/camel-activemq/src/main/java/org/apache/camel/component/activemq/ActiveMQEndpoint.java
@@ -25,12 +25,14 @@ import org.apache.camel.component.jms.JmsComponent;
import org.apache.camel.component.jms.JmsConfiguration;
import org.apache.camel.component.jms.JmsEndpoint;
import org.apache.camel.spi.EndpointServiceLocation;
+import org.apache.camel.spi.Metadata;
import org.apache.camel.spi.UriEndpoint;
import org.apache.camel.spi.UriParam;
/**
* Send messages to (or consume from) Apache ActiveMQ 5.x. This component
extends the Camel JMS component.
*/
+@Metadata(aliases = { "amq" })
@UriEndpoint(firstVersion = "1.0.0", extendsScheme = "jms", scheme =
"activemq", title = "ActiveMQ 5.x",
syntax = "activemq:destinationType:destinationName",
category = { Category.MESSAGING })
diff --git
a/components/camel-activemq6/src/generated/resources/META-INF/org/apache/camel/component/activemq6/activemq6.json
b/components/camel-activemq6/src/generated/resources/META-INF/org/apache/camel/component/activemq6/activemq6.json
index 04ddf3b3a40b..b1e04a0ba8b4 100644
---
a/components/camel-activemq6/src/generated/resources/META-INF/org/apache/camel/component/activemq6/activemq6.json
+++
b/components/camel-activemq6/src/generated/resources/META-INF/org/apache/camel/component/activemq6/activemq6.json
@@ -9,6 +9,7 @@
"label": "messaging",
"javaType": "org.apache.camel.component.activemq6.ActiveMQComponent",
"supportLevel": "Stable",
+ "aliases": [ "amq" ],
"groupId": "org.apache.camel",
"artifactId": "camel-activemq6",
"version": "4.23.0-SNAPSHOT",
diff --git
a/components/camel-activemq6/src/main/java/org/apache/camel/component/activemq6/ActiveMQEndpoint.java
b/components/camel-activemq6/src/main/java/org/apache/camel/component/activemq6/ActiveMQEndpoint.java
index 877e2fb8a4bf..cd3bed8b2bba 100644
---
a/components/camel-activemq6/src/main/java/org/apache/camel/component/activemq6/ActiveMQEndpoint.java
+++
b/components/camel-activemq6/src/main/java/org/apache/camel/component/activemq6/ActiveMQEndpoint.java
@@ -25,12 +25,14 @@ import org.apache.camel.component.jms.JmsComponent;
import org.apache.camel.component.jms.JmsConfiguration;
import org.apache.camel.component.jms.JmsEndpoint;
import org.apache.camel.spi.EndpointServiceLocation;
+import org.apache.camel.spi.Metadata;
import org.apache.camel.spi.UriEndpoint;
import org.apache.camel.spi.UriParam;
/**
* Send messages to (or consume from) Apache ActiveMQ 6.x. This component
extends the Camel JMS component.
*/
+@Metadata(aliases = { "amq" })
@UriEndpoint(firstVersion = "4.7.0", extendsScheme = "jms", scheme =
"activemq6", title = "ActiveMQ 6.x",
syntax = "activemq6:destinationType:destinationName",
category = { Category.MESSAGING })
diff --git
a/components/camel-mail/src/generated/resources/META-INF/org/apache/camel/component/mail/imap.json
b/components/camel-mail/src/generated/resources/META-INF/org/apache/camel/component/mail/imap.json
index 6c49e15393b5..621ba167453a 100644
---
a/components/camel-mail/src/generated/resources/META-INF/org/apache/camel/component/mail/imap.json
+++
b/components/camel-mail/src/generated/resources/META-INF/org/apache/camel/component/mail/imap.json
@@ -9,6 +9,7 @@
"label": "mail",
"javaType": "org.apache.camel.component.mail.MailComponent",
"supportLevel": "Stable",
+ "aliases": [ "mail", "email" ],
"groupId": "org.apache.camel",
"artifactId": "camel-mail",
"version": "4.23.0-SNAPSHOT",
diff --git
a/components/camel-mail/src/generated/resources/META-INF/org/apache/camel/component/mail/imaps.json
b/components/camel-mail/src/generated/resources/META-INF/org/apache/camel/component/mail/imaps.json
index 2d59fa225fa5..be87ed8c11ae 100644
---
a/components/camel-mail/src/generated/resources/META-INF/org/apache/camel/component/mail/imaps.json
+++
b/components/camel-mail/src/generated/resources/META-INF/org/apache/camel/component/mail/imaps.json
@@ -9,6 +9,7 @@
"label": "mail",
"javaType": "org.apache.camel.component.mail.MailComponent",
"supportLevel": "Stable",
+ "aliases": [ "mail", "email" ],
"groupId": "org.apache.camel",
"artifactId": "camel-mail",
"version": "4.23.0-SNAPSHOT",
diff --git
a/components/camel-mail/src/generated/resources/META-INF/org/apache/camel/component/mail/pop3.json
b/components/camel-mail/src/generated/resources/META-INF/org/apache/camel/component/mail/pop3.json
index 6827a27d73bf..e868fcf6abdd 100644
---
a/components/camel-mail/src/generated/resources/META-INF/org/apache/camel/component/mail/pop3.json
+++
b/components/camel-mail/src/generated/resources/META-INF/org/apache/camel/component/mail/pop3.json
@@ -9,6 +9,7 @@
"label": "mail",
"javaType": "org.apache.camel.component.mail.MailComponent",
"supportLevel": "Stable",
+ "aliases": [ "mail", "email" ],
"groupId": "org.apache.camel",
"artifactId": "camel-mail",
"version": "4.23.0-SNAPSHOT",
diff --git
a/components/camel-mail/src/generated/resources/META-INF/org/apache/camel/component/mail/pop3s.json
b/components/camel-mail/src/generated/resources/META-INF/org/apache/camel/component/mail/pop3s.json
index 582c2818dc8a..d2e95187a967 100644
---
a/components/camel-mail/src/generated/resources/META-INF/org/apache/camel/component/mail/pop3s.json
+++
b/components/camel-mail/src/generated/resources/META-INF/org/apache/camel/component/mail/pop3s.json
@@ -9,6 +9,7 @@
"label": "mail",
"javaType": "org.apache.camel.component.mail.MailComponent",
"supportLevel": "Stable",
+ "aliases": [ "mail", "email" ],
"groupId": "org.apache.camel",
"artifactId": "camel-mail",
"version": "4.23.0-SNAPSHOT",
diff --git
a/components/camel-mail/src/generated/resources/META-INF/org/apache/camel/component/mail/smtp.json
b/components/camel-mail/src/generated/resources/META-INF/org/apache/camel/component/mail/smtp.json
index c0cd0d423a4e..33dff5f867f5 100644
---
a/components/camel-mail/src/generated/resources/META-INF/org/apache/camel/component/mail/smtp.json
+++
b/components/camel-mail/src/generated/resources/META-INF/org/apache/camel/component/mail/smtp.json
@@ -9,6 +9,7 @@
"label": "mail",
"javaType": "org.apache.camel.component.mail.MailComponent",
"supportLevel": "Stable",
+ "aliases": [ "mail", "email" ],
"groupId": "org.apache.camel",
"artifactId": "camel-mail",
"version": "4.23.0-SNAPSHOT",
diff --git
a/components/camel-mail/src/generated/resources/META-INF/org/apache/camel/component/mail/smtps.json
b/components/camel-mail/src/generated/resources/META-INF/org/apache/camel/component/mail/smtps.json
index c5c1721f6c6a..2b2188d35521 100644
---
a/components/camel-mail/src/generated/resources/META-INF/org/apache/camel/component/mail/smtps.json
+++
b/components/camel-mail/src/generated/resources/META-INF/org/apache/camel/component/mail/smtps.json
@@ -9,6 +9,7 @@
"label": "mail",
"javaType": "org.apache.camel.component.mail.MailComponent",
"supportLevel": "Stable",
+ "aliases": [ "mail", "email" ],
"groupId": "org.apache.camel",
"artifactId": "camel-mail",
"version": "4.23.0-SNAPSHOT",
diff --git
a/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailEndpoint.java
b/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailEndpoint.java
index fddb518f54a8..7280476da01a 100644
---
a/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailEndpoint.java
+++
b/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailEndpoint.java
@@ -30,6 +30,7 @@ import org.apache.camel.spi.EndpointServiceLocation;
import org.apache.camel.spi.HeaderFilterStrategy;
import org.apache.camel.spi.HeaderFilterStrategyAware;
import org.apache.camel.spi.IdempotentRepository;
+import org.apache.camel.spi.Metadata;
import org.apache.camel.spi.UriEndpoint;
import org.apache.camel.spi.UriParam;
import org.apache.camel.support.ScheduledPollEndpoint;
@@ -42,6 +43,7 @@ import static
org.apache.camel.component.mail.MailConstants.MAIL_HANDLE_DUPLICAT
/**
* Send and receive emails using imap, pop3 and smtp protocols.
*/
+@Metadata(aliases = { "mail", "email" })
@UriEndpoint(firstVersion = "1.0.0", scheme =
"imap,imaps,pop3,pop3s,smtp,smtps", title = "IMAP,IMAPS,POP3,POP3S,SMTP,SMTPS",
syntax = "imap:host:port", alternativeSyntax =
"imap:username:password@host:port",
category = { Category.MAIL }, headersClass = MailConstants.class)
diff --git a/docs/user-manual/modules/ROOT/pages/camel-catalog.adoc
b/docs/user-manual/modules/ROOT/pages/camel-catalog.adoc
index ec08bff1087c..7f63d0149d28 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-catalog.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-catalog.adoc
@@ -88,6 +88,40 @@ nesting level in the YAML DSL, with types, descriptions,
required flags, default
and enum choices. It can be used by third-party tooling (editors, IDE plugins,
visual
designers) to provide context-aware code completion and validation for YAML
DSL routes.
+=== Finding components by protocol or product name
+
+People, and AI agents driving Camel through tooling, often refer to a
component by the protocol or
+product it connects to rather than by its Camel scheme: _mqtt_ (the component
is `paho-mqtt5`),
+_s3_ (`aws2-s3`), _rabbitmq_ (`spring-rabbitmq`), _pubsub_ (`google-pubsub`).
The catalog can look
+components, data formats and languages up by such a term, ranking the best
matches first:
+the exact scheme or name, then declared aliases, alternative schemes, words of
the title, words of the
+scheme or name, and finally names containing the term. A component that shares
one implementation under
+several schemes (such as `imap`, `pop3` and `smtp`) is returned once.
+
+[source,java]
+----
+CamelCatalog catalog = new DefaultCamelCatalog();
+
+catalog.suggestComponentNames("mqtt", 5); // [paho-mqtt5]
+catalog.suggestComponentNames("s3", 5); // [aws2-s3, aws2-s3-vectors]
+catalog.suggestComponentNames("amq", 5); // [activemq, activemq6, amqp]
+catalog.suggestComponentNames("aws", 5); // at most five of the many
AWS components
+catalog.suggestDataFormatNames("yaml", 5); // [snakeYaml]
+catalog.suggestLanguageNames("path", 5); // [jsonpath, xpath]
+----
+
+Component developers can declare the shorthands a title cannot provide with
the `aliases` attribute of
+`@Metadata` on the endpoint class, as the mail component does for _mail_ and
_email_:
+
+[source,java]
+----
+@Metadata(aliases = { "mail", "email" })
+@UriEndpoint(firstVersion = "1.0.0", scheme =
"imap,imaps,pop3,pop3s,smtp,smtps", ...)
+public class MailEndpoint extends ScheduledPollEndpoint {
+----
+
+Aliases are descriptive names for discovery only; they cannot be used as the
scheme in an endpoint URI.
+
=== Documentation in the Catalog
The catalog includes the AsciiDoc documentation pages from all modules. This
makes the full
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogBaseCommand.java
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogBaseCommand.java
index b8ac84ee7605..f872d2d5cfac 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogBaseCommand.java
+++
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogBaseCommand.java
@@ -96,6 +96,13 @@ public abstract class CatalogBaseCommand extends
CamelCommand {
abstract List<Row> collectRows();
+ /**
+ * Names the catalog suggests for a filter that matched nothing, such as a
protocol or product name (mqtt, s3).
+ */
+ List<String> suggestNames(String term) {
+ return List.of();
+ }
+
String getGAV(ArtifactModel<?> model) {
return model.getGroupId() + ":" + model.getArtifactId() + ":" +
model.getVersion();
}
@@ -186,7 +193,12 @@ public abstract class CatalogBaseCommand extends
CamelCommand {
} else if (filterName != null) {
// suggest similar names when filter returns no results
List<String> allNames = collectRows().stream().map(r ->
r.name).collect(Collectors.toList());
- List<String> suggestions =
SuggestSimilarHelper.didYouMean(allNames, filterName);
+ List<String> suggestions = new
ArrayList<>(suggestNames(filterName));
+ for (String similar : SuggestSimilarHelper.didYouMean(allNames,
filterName)) {
+ if (!suggestions.contains(similar)) {
+ suggestions.add(similar);
+ }
+ }
if (!suggestions.isEmpty()) {
printer().println("No results for filter: " + filterName + ".
Did you mean? " + String.join(", ", suggestions));
} else {
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogComponent.java
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogComponent.java
index 154e96b3f38e..99c766667b6f 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogComponent.java
+++
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogComponent.java
@@ -57,4 +57,9 @@ public class CatalogComponent extends CatalogBaseCommand {
return rows;
}
+ @Override
+ List<String> suggestNames(String term) {
+ return catalog.suggestComponentNames(term, 5);
+ }
+
}
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogDataFormat.java
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogDataFormat.java
index 14c06a37723b..c785dbb0aa49 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogDataFormat.java
+++
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogDataFormat.java
@@ -57,4 +57,9 @@ public class CatalogDataFormat extends CatalogBaseCommand {
return rows;
}
+ @Override
+ List<String> suggestNames(String term) {
+ return catalog.suggestDataFormatNames(term, 5);
+ }
+
}
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogLanguage.java
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogLanguage.java
index 3d641290c184..a1e8a672b17a 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogLanguage.java
+++
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogLanguage.java
@@ -58,4 +58,9 @@ public class CatalogLanguage extends CatalogBaseCommand {
return rows;
}
+ @Override
+ List<String> suggestNames(String term) {
+ return catalog.suggestLanguageNames(term, 5);
+ }
+
}
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogComponentTest.java
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogComponentTest.java
index e5dd1ed0a6c9..fd0b15bd4a0e 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogComponentTest.java
+++
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogComponentTest.java
@@ -70,6 +70,17 @@ class CatalogComponentTest extends
CamelCommandBaseTestSupport {
"JSON output should contain a row with name kafka, was: " +
printer.getOutput());
}
+ @Test
+ void shouldSuggestComponentByProtocolOrProductName() throws Exception {
+ CatalogComponent command = createCommand();
+ command.filterName = "servicebus";
+ int exit = command.doCall();
+ assertEquals(0, exit);
+ String out = printer.getOutput();
+ assertTrue(out.contains("Did you mean? azure-servicebus"),
+ "a product name should suggest the component using it, was: "
+ out);
+ }
+
@Test
void shouldSuggestSimilarWhenFilterHasNoMatch() throws Exception {
CatalogComponent command = createCommand();
diff --git
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiToolRegistry.java
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiToolRegistry.java
index cdd87230ae94..8b58e480f158 100644
---
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiToolRegistry.java
+++
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiToolRegistry.java
@@ -1608,17 +1608,16 @@ class TuiToolRegistry {
return null;
}
String scheme = endpoint.substring(0, colon).toLowerCase();
- List<String> names;
+ List<String> similar;
try {
CamelCatalog catalog = CatalogLoader.loadCatalog(null,
facade.getSelectedCamelVersion(), true);
- names = catalog.findComponentNames();
+ if (catalog.findComponentNames().contains(scheme)) {
+ return null;
+ }
+ similar = catalog.suggestComponentNames(scheme, 5);
} catch (Exception e) {
return null;
}
- if (names.contains(scheme)) {
- return null;
- }
- List<String> similar = suggestComponents(scheme, names);
if (similar.isEmpty()) {
return "Camel has no component named '" + scheme + "'. Use
tui_catalog_doc to find the right component, "
+ "then send again with its scheme.";
@@ -1628,40 +1627,6 @@ class TuiToolRegistry {
+ endpoint.substring(colon) + "'.";
}
- /** Well-known names people use for a protocol that differ from the Camel
component name. */
- private static final Map<String, List<String>> SCHEME_ALIASES = Map.of(
- "mqtt", List.of("paho-mqtt5", "paho"),
- "mqtt5", List.of("paho-mqtt5"),
- "rabbitmq", List.of("spring-rabbitmq"),
- "amq", List.of("activemq", "jms"),
- "rest", List.of("rest", "platform-http", "http"),
- "s3", List.of("aws2-s3"),
- "sqs", List.of("aws2-sqs"),
- "sns", List.of("aws2-sns"),
- "pubsub", List.of("google-pubsub"),
- "servicebus", List.of("azure-servicebus"));
-
- /**
- * Catalog component names that resemble the scheme: known aliases first,
then names containing the scheme (or
- * contained in it), at most five.
- */
- static List<String> suggestComponents(String scheme, List<String>
componentNames) {
- List<String> result = new ArrayList<>();
- for (String alias : SCHEME_ALIASES.getOrDefault(scheme, List.of())) {
- if (componentNames.contains(alias) && !result.contains(alias)) {
- result.add(alias);
- }
- }
- if (scheme.length() >= 3) {
- for (String name : componentNames) {
- if ((name.contains(scheme) || scheme.contains(name)) &&
!name.equals(scheme) && !result.contains(name)) {
- result.add(name);
- }
- }
- }
- return result.size() > 5 ? result.subList(0, 5) : result;
- }
-
private String callExecuteSql(Map<String, Object> args) {
String query = (String) args.get("query");
if (query == null || query.isBlank()) {
@@ -1939,7 +1904,7 @@ class TuiToolRegistry {
return buildComponentDocJson(cm, lowerFilter, includeOptions,
doc);
}
if (kind != null) {
- return "{\"error\": \"Component not found: " + name + "\"}";
+ return notFound("Component", name,
catalog.suggestComponentNames(name, 5));
}
}
if (kind == null || "dataformat".equals(kind)) {
@@ -1949,7 +1914,7 @@ class TuiToolRegistry {
return buildDataFormatDocJson(dm, lowerFilter, includeOptions,
doc);
}
if (kind != null) {
- return "{\"error\": \"Data format not found: " + name + "\"}";
+ return notFound("Data format", name,
catalog.suggestDataFormatNames(name, 5));
}
}
if (kind == null || "language".equals(kind)) {
@@ -1959,7 +1924,7 @@ class TuiToolRegistry {
return buildLanguageDocJson(lm, lowerFilter, includeOptions,
doc);
}
if (kind != null) {
- return "{\"error\": \"Language not found: " + name + "\"}";
+ return notFound("Language", name,
catalog.suggestLanguageNames(name, 5));
}
}
if (kind == null || "eip".equals(kind)) {
@@ -1972,7 +1937,23 @@ class TuiToolRegistry {
return "{\"error\": \"EIP not found: " + name + "\"}";
}
}
- return "{\"error\": \"Artifact not found: " + name + "\"}";
+ List<String> suggestions = new
ArrayList<>(catalog.suggestComponentNames(name, 5));
+ suggestions.addAll(catalog.suggestDataFormatNames(name, 3));
+ suggestions.addAll(catalog.suggestLanguageNames(name, 3));
+ return notFound("Artifact", name, suggestions);
+ }
+
+ /**
+ * Error for a catalog lookup that found nothing, with the names the
catalog suggests for the term (a protocol or
+ * product name such as mqtt or s3) so the next call can use one of them.
+ */
+ private static String notFound(String kind, String name, List<String>
suggestions) {
+ JsonObject error = new JsonObject();
+ error.put("error", kind + " not found: " + name);
+ if (!suggestions.isEmpty()) {
+ error.put("suggestions", new JsonArray(suggestions));
+ }
+ return error.toJson();
}
@SuppressWarnings("unchecked")
diff --git
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiToolRegistrySuggestComponentsTest.java
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiToolRegistrySuggestComponentsTest.java
deleted file mode 100644
index 95e48a617124..000000000000
---
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiToolRegistrySuggestComponentsTest.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.dsl.jbang.core.commands.tui;
-
-import java.util.List;
-
-import org.junit.jupiter.api.Test;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-class TuiToolRegistrySuggestComponentsTest {
-
- private static final List<String> NAMES = List.of("activemq", "aws2-s3",
"aws2-sqs", "http", "jms", "kafka",
- "paho", "paho-mqtt5", "platform-http", "rest", "spring-rabbitmq",
"timer");
-
- @Test
- void knownAliasesComeFirst() {
- assertEquals(List.of("paho-mqtt5", "paho"),
TuiToolRegistry.suggestComponents("mqtt", NAMES));
- assertEquals(List.of("spring-rabbitmq"),
TuiToolRegistry.suggestComponents("rabbitmq", NAMES));
- assertEquals(List.of("aws2-s3"),
TuiToolRegistry.suggestComponents("s3", NAMES));
- }
-
- @Test
- void substringMatchesFillInWhenThereIsNoAlias() {
- assertEquals(List.of("http"),
TuiToolRegistry.suggestComponents("https", NAMES));
- assertEquals(List.of("paho", "paho-mqtt5"),
TuiToolRegistry.suggestComponents("paho-mqtt", NAMES));
- assertTrue(TuiToolRegistry.suggestComponents("xyz", NAMES).isEmpty());
- // very short schemes would match too much, so they only get alias hits
- assertTrue(TuiToolRegistry.suggestComponents("mq", NAMES).isEmpty());
- }
-}
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 6be3dfa1237a..7fde90d74c5f 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
@@ -859,6 +859,12 @@ public class EndpointSchemaGeneratorMojo extends
AbstractGeneratorMojo {
model.setFirstVersion(firstVersion);
}
+ // aliases (protocol or product names people use for the component)
come from @Metadata on the endpoint class
+ Metadata endpointMetadata =
endpointClassElement.getAnnotation(Metadata.class);
+ if (endpointMetadata != null && endpointMetadata.aliases().length > 0)
{
+ model.setAliases(new
ArrayList<>(Arrays.asList(endpointMetadata.aliases())));
+ }
+
model.setDescription(project.getDescription());
model.setGroupId(project.getGroupId());
model.setArtifactId(project.getArtifactId());