This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch feat/camel-tui in repository https://gitbox.apache.org/repos/asf/camel.git
commit 6c9b2fba3bf80bc9b1a303a079865753c5f481b9 Author: Claus Ibsen <[email protected]> AuthorDate: Mon May 18 14:55:37 2026 +0200 TUI: expose specificationUri in RestRegistry and HTTP detail panel Thread the OpenAPI spec file path from RestOpenApiEndpoint through the registry to the TUI so the HTTP detail panel shows which spec file backs each contract-first route. - RestRegistry.RestService: add getSpecificationUri() (@Nullable, 4.21) - RestRegistry.addRestService(): add specificationUri parameter - DefaultRestRegistry: store and expose specificationUri in RestServiceEntry - RestOpenApiProcessor: passes endpoint.getSpecificationUri() when registering - RestEndpoint (REST DSL): passes null (code-first has no spec URI) - RestDevConsole: emits specificationUri in JSON and text output when present - CamelMonitor HTTP detail panel: shows Spec: <uri> when specificationUri is set Viewing the spec content via a key will be added separately (requires Camel ResourceResolver to handle classpath: and file: URIs). Co-Authored-By: Claude Sonnet 4.6 <[email protected]> --- .../rest/openapi/RestOpenApiProcessor.java | 3 +- .../camel/component/rest/DefaultRestRegistry.java | 16 ++++++--- .../apache/camel/component/rest/RestEndpoint.java | 3 +- .../component/rest/DefaultRestRegistryTest.java | 22 ++++++------ .../component/rest/RestRegistryStatefulTest.java | 6 ++-- .../java/org/apache/camel/spi/RestRegistry.java | 41 ++++++++++++++-------- .../apache/camel/impl/console/RestDevConsole.java | 6 ++++ .../dsl/jbang/core/commands/tui/CamelMonitor.java | 5 +++ 8 files changed, 67 insertions(+), 35 deletions(-) diff --git a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiProcessor.java b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiProcessor.java index c2680dda5eb6..a40a91f034a7 100644 --- a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiProcessor.java +++ b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiProcessor.java @@ -174,7 +174,8 @@ public class RestOpenApiProcessor extends AsyncProcessorSupport implements Camel } RestRegistry restRegistry = PluginHelper.getRestRegistry(camelContext); restRegistry.addRestService(consumer, true, url, path, basePath, null, v, bc.getConsumes(), - bc.getProduces(), bc.getType(), bc.getOutType(), routeId, operationId, desc); + bc.getProduces(), bc.getType(), bc.getOutType(), routeId, operationId, + endpoint.getSpecificationUri(), desc); try { RestBindingAdvice binding = RestBindingAdviceFactory.build(camelContext, bc); diff --git a/components/camel-rest/src/main/java/org/apache/camel/component/rest/DefaultRestRegistry.java b/components/camel-rest/src/main/java/org/apache/camel/component/rest/DefaultRestRegistry.java index 550b53cdcf6a..a29283973f64 100644 --- a/components/camel-rest/src/main/java/org/apache/camel/component/rest/DefaultRestRegistry.java +++ b/components/camel-rest/src/main/java/org/apache/camel/component/rest/DefaultRestRegistry.java @@ -51,10 +51,10 @@ public class DefaultRestRegistry extends ServiceSupport implements RestRegistry, Consumer consumer, boolean contractFirst, String url, String baseUrl, String basePath, String uriTemplate, String method, String consumes, String produces, String inType, String outType, String routeId, String operationId, - String description) { + String specificationUri, String description) { RestServiceEntry entry = new RestServiceEntry( consumer, false, contractFirst, url, baseUrl, basePath, uriTemplate, method, consumes, produces, inType, - outType, routeId, operationId, description); + outType, routeId, operationId, specificationUri, description); List<RestService> list = registry.computeIfAbsent(consumer, c -> new ArrayList<>()); list.add(entry); } @@ -65,7 +65,7 @@ public class DefaultRestRegistry extends ServiceSupport implements RestRegistry, String produces, String description) { RestServiceEntry entry = new RestServiceEntry( consumer, true, contractFirst, url, baseUrl, basePath, null, method, null, produces, null, null, null, - null, description); + null, null, description); List<RestService> list = specs.computeIfAbsent(consumer, c -> new ArrayList<>()); list.add(entry); } @@ -205,12 +205,14 @@ public class DefaultRestRegistry extends ServiceSupport implements RestRegistry, private final String outType; private final String routeId; private final String operationId; + private final String specificationUri; private final String description; private RestServiceEntry(Consumer consumer, boolean specification, boolean contractFirst, String url, String baseUrl, String basePath, String uriTemplate, String method, String consumes, String produces, - String inType, String outType, String routeId, String operationId, String description) { + String inType, String outType, String routeId, String operationId, + String specificationUri, String description) { this.consumer = consumer; this.specification = specification; this.contractFirst = contractFirst; @@ -225,6 +227,7 @@ public class DefaultRestRegistry extends ServiceSupport implements RestRegistry, this.outType = outType; this.routeId = routeId; this.operationId = operationId; + this.specificationUri = specificationUri; this.description = description; } @@ -312,6 +315,11 @@ public class DefaultRestRegistry extends ServiceSupport implements RestRegistry, return operationId; } + @Override + public String getSpecificationUri() { + return specificationUri; + } + @Override public String getDescription() { return description; diff --git a/components/camel-rest/src/main/java/org/apache/camel/component/rest/RestEndpoint.java b/components/camel-rest/src/main/java/org/apache/camel/component/rest/RestEndpoint.java index 710f31b96d45..926695b042fe 100644 --- a/components/camel-rest/src/main/java/org/apache/camel/component/rest/RestEndpoint.java +++ b/components/camel-rest/src/main/java/org/apache/camel/component/rest/RestEndpoint.java @@ -489,7 +489,8 @@ public class RestEndpoint extends DefaultEndpoint { // add to rest registry, so we can keep track of them RestRegistry registry = PluginHelper.getRestRegistry(getCamelContext()); registry.addRestService(consumer, false, url, baseUrl, getPath(), getUriTemplate(), - getMethod(), getConsumes(), getProduces(), getInType(), getOutType(), getRouteId(), null, getDescription()); + getMethod(), getConsumes(), getProduces(), getInType(), getOutType(), getRouteId(), null, null, + getDescription()); return consumer; } diff --git a/components/camel-rest/src/test/java/org/apache/camel/component/rest/DefaultRestRegistryTest.java b/components/camel-rest/src/test/java/org/apache/camel/component/rest/DefaultRestRegistryTest.java index 260e9983b46d..0d5c818106f2 100644 --- a/components/camel-rest/src/test/java/org/apache/camel/component/rest/DefaultRestRegistryTest.java +++ b/components/camel-rest/src/test/java/org/apache/camel/component/rest/DefaultRestRegistryTest.java @@ -62,7 +62,7 @@ class DefaultRestRegistryTest { registry.addRestService(consumer1, false, "http://localhost:8080/api/users", "http://localhost:8080", "/api", "/users", "GET", "application/json", "application/json", "User", "User", - "route1", null, "Get all users"); + "route1", null, null, "Get all users"); assertThat(registry.size()).isEqualTo(1); } @@ -72,12 +72,12 @@ class DefaultRestRegistryTest { registry.addRestService(consumer1, false, "http://localhost:8080/api/users", "http://localhost:8080", "/api", "/users", "GET", "application/json", "application/json", null, null, - "route1", null, "Get all users"); + "route1", null, null, "Get all users"); registry.addRestService(consumer2, false, "http://localhost:8080/api/orders", "http://localhost:8080", "/api", "/orders", "POST", "application/json", "application/json", "Order", "Order", - "route2", null, "Create order"); + "route2", null, null, "Create order"); assertThat(registry.size()).isEqualTo(2); } @@ -86,11 +86,11 @@ class DefaultRestRegistryTest { void testAddMultipleServicesToSameConsumer() { registry.addRestService(consumer1, false, "http://localhost:8080/api/users", "http://localhost:8080", "/api", "/users", "GET", - null, null, null, null, "route1", null, "Get users"); + null, null, null, null, "route1", null, null, "Get users"); registry.addRestService(consumer1, false, "http://localhost:8080/api/users/{id}", "http://localhost:8080", "/api", "/users/{id}", "GET", - null, null, null, null, "route2", null, "Get user by id"); + null, null, null, null, "route2", null, null, "Get user by id"); assertThat(registry.size()).isEqualTo(2); } @@ -99,7 +99,7 @@ class DefaultRestRegistryTest { void testRemoveRestService() { registry.addRestService(consumer1, false, "http://localhost:8080/api/users", "http://localhost:8080", "/api", "/users", "GET", - null, null, null, null, "route1", null, "Get users"); + null, null, null, null, "route1", null, null, "Get users"); assertThat(registry.size()).isEqualTo(1); @@ -112,7 +112,7 @@ class DefaultRestRegistryTest { void testRemoveNonExistentService() { registry.addRestService(consumer1, false, "http://localhost:8080/api/users", "http://localhost:8080", "/api", "/users", "GET", - null, null, null, null, "route1", null, "Get users"); + null, null, null, null, "route1", null, null, "Get users"); registry.removeRestService(consumer2); @@ -124,7 +124,7 @@ class DefaultRestRegistryTest { registry.addRestService(consumer1, false, "http://localhost:8080/api/users", "http://localhost:8080", "/api", "/users", "GET", "application/json", "application/json", "User", "UserResponse", - "route1", null, "Get all users"); + "route1", null, null, "Get all users"); List<RestRegistry.RestService> services = registry.listAllRestServices(); @@ -149,7 +149,7 @@ class DefaultRestRegistryTest { void testContractFirstService() { registry.addRestService(consumer1, true, "http://localhost:8080/api/users", "http://localhost:8080", "/api", "/users", "GET", - null, null, null, null, "route1", null, "Get users"); + null, null, null, null, "route1", null, null, "Get users"); List<RestRegistry.RestService> services = registry.listAllRestServices(); assertThat(services.get(0).isContractFirst()).isTrue(); @@ -170,7 +170,7 @@ class DefaultRestRegistryTest { void testServiceState() { registry.addRestService(consumer1, false, "http://localhost:8080/api/users", "http://localhost:8080", "/api", "/users", "GET", - null, null, null, null, "route1", null, "Get users"); + null, null, null, null, "route1", null, null, "Get users"); List<RestRegistry.RestService> services = registry.listAllRestServices(); // Non-stateful consumer returns Stopped state @@ -187,7 +187,7 @@ class DefaultRestRegistryTest { void testStopClearsRegistry() throws Exception { registry.addRestService(consumer1, false, "http://localhost:8080/api/users", "http://localhost:8080", "/api", "/users", "GET", - null, null, null, null, "route1", null, "Get users"); + null, null, null, null, "route1", null, null, "Get users"); assertThat(registry.size()).isEqualTo(1); diff --git a/components/camel-rest/src/test/java/org/apache/camel/component/rest/RestRegistryStatefulTest.java b/components/camel-rest/src/test/java/org/apache/camel/component/rest/RestRegistryStatefulTest.java index 7cf4922dc710..334afe6bfac8 100644 --- a/components/camel-rest/src/test/java/org/apache/camel/component/rest/RestRegistryStatefulTest.java +++ b/components/camel-rest/src/test/java/org/apache/camel/component/rest/RestRegistryStatefulTest.java @@ -73,7 +73,7 @@ class RestRegistryStatefulTest { registry.addRestService(consumer, false, "http://localhost:8080/api/users", "http://localhost:8080", "/api", "/users", "GET", "application/json", "application/json", null, null, - "route1", null, "Get users"); + "route1", null, null, "Get users"); List<RestRegistry.RestService> services = registry.listAllRestServices(); assertThat(services).hasSize(1); @@ -101,7 +101,7 @@ class RestRegistryStatefulTest { registry.addRestService(consumer, false, "http://localhost:8080/api/orders", "http://localhost:8080", "/api", "/orders", "POST", - null, null, null, null, "route2", null, "Create order"); + null, null, null, null, "route2", null, null, "Create order"); List<RestRegistry.RestService> services = registry.listAllRestServices(); assertThat(services.get(0).getState()).isEqualTo("Started"); @@ -117,7 +117,7 @@ class RestRegistryStatefulTest { registry.addRestService(consumer, false, "http://localhost:8080/api/items", "http://localhost:8080", "/api", "/items", "DELETE", - null, null, null, null, "route3", null, "Delete item"); + null, null, null, null, "route3", null, null, "Delete item"); List<RestRegistry.RestService> services = registry.listAllRestServices(); assertThat(services.get(0).getState()).isEqualTo("Suspended"); diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/RestRegistry.java b/core/camel-api/src/main/java/org/apache/camel/spi/RestRegistry.java index 852d3610e615..f5468065001d 100644 --- a/core/camel-api/src/main/java/org/apache/camel/spi/RestRegistry.java +++ b/core/camel-api/src/main/java/org/apache/camel/spi/RestRegistry.java @@ -129,31 +129,42 @@ public interface RestRegistry extends StaticService { @Nullable String getDescription(); + /** + * Gets the specification URI of the OpenAPI contract (contract-first routes only), e.g. {@code petstore.yaml} + * or {@code classpath:openapi.json}. + * + * @since 4.21 + */ + @Nullable + String getSpecificationUri(); + } /** * Adds a new REST service to the registry. * - * @param consumer the consumer - * @param contractFirst is the rest service based on code-first or contract-first - * @param url the absolute url of the REST service - * @param baseUrl the base url of the REST service - * @param basePath the base path - * @param uriTemplate the uri template - * @param method the HTTP method - * @param consumes optional details about what media-types the REST service accepts - * @param produces optional details about what media-types the REST service returns - * @param inType optional detail input binding to a FQN class name - * @param outType optional detail output binding to a FQN class name - * @param routeId the id of the route this rest service will be using - * @param operationId optional operationId from the OpenAPI contract - * @param description optional description about the service + * @param consumer the consumer + * @param contractFirst is the rest service based on code-first or contract-first + * @param url the absolute url of the REST service + * @param baseUrl the base url of the REST service + * @param basePath the base path + * @param uriTemplate the uri template + * @param method the HTTP method + * @param consumes optional details about what media-types the REST service accepts + * @param produces optional details about what media-types the REST service returns + * @param inType optional detail input binding to a FQN class name + * @param outType optional detail output binding to a FQN class name + * @param routeId the id of the route this rest service will be using + * @param operationId optional operationId from the OpenAPI contract + * @param specificationUri optional URI of the OpenAPI spec file (contract-first only) + * @param description optional description about the service */ void addRestService( Consumer consumer, boolean contractFirst, String url, String baseUrl, String basePath, @Nullable String uriTemplate, String method, @Nullable String consumes, @Nullable String produces, @Nullable String inType, @Nullable String outType, - String routeId, @Nullable String operationId, @Nullable String description); + String routeId, @Nullable String operationId, @Nullable String specificationUri, + @Nullable String description); /** * Removes the REST service from the registry diff --git a/core/camel-console/src/main/java/org/apache/camel/impl/console/RestDevConsole.java b/core/camel-console/src/main/java/org/apache/camel/impl/console/RestDevConsole.java index 73a80ea85919..dba1d20bc517 100644 --- a/core/camel-console/src/main/java/org/apache/camel/impl/console/RestDevConsole.java +++ b/core/camel-console/src/main/java/org/apache/camel/impl/console/RestDevConsole.java @@ -55,6 +55,9 @@ public class RestDevConsole extends AbstractDevConsole { if (rs.getOperationId() != null) { sb.append(String.format("%n Operation Id: %s", rs.getOperationId())); } + if (rs.getSpecificationUri() != null) { + sb.append(String.format("%n Specification: %s", rs.getSpecificationUri())); + } if (rs.getConsumes() != null) { sb.append(String.format("%n Consumes: %s", rs.getConsumes())); } @@ -99,6 +102,9 @@ public class RestDevConsole extends AbstractDevConsole { if (rs.getOperationId() != null) { jo.put("operationId", rs.getOperationId()); } + if (rs.getSpecificationUri() != null) { + jo.put("specificationUri", rs.getSpecificationUri()); + } if (rs.getConsumes() != null) { jo.put("consumes", rs.getConsumes()); } diff --git a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java index f74897c9b834..ad69260b49d0 100644 --- a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java +++ b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java @@ -3693,6 +3693,9 @@ public class CamelMonitor extends CamelCommand { if (ep.operationId != null) { addDetailLine(lines, "Operation", ep.operationId); } + if (ep.specificationUri != null) { + addDetailLine(lines, "Spec", ep.specificationUri); + } if (ep.state != null) { addDetailLine(lines, "State", ep.state); } @@ -5431,6 +5434,7 @@ public class CamelMonitor extends CamelCommand { ep.specification = Boolean.TRUE.equals(rj.get("specification")); ep.routeId = rj.getString("routeId"); ep.operationId = rj.getString("operationId"); + ep.specificationUri = rj.getString("specificationUri"); ep.state = rj.getString("state"); ep.inType = rj.getString("inType"); ep.outType = rj.getString("outType"); @@ -5772,6 +5776,7 @@ public class CamelMonitor extends CamelCommand { boolean specification; // true = OpenAPI/Swagger spec endpoint String routeId; String operationId; + String specificationUri; String description; String inType; String outType;
