You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ac...@apache.org on 2020/07/21 09:12:04 UTC
[camel-spring-boot] branch master updated:
"CAMEL-15274:camel-spring-boot - Add back http endpoint for route
information"
This is an automated email from the ASF dual-hosted git repository.
acosentino pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel-spring-boot.git
The following commit(s) were added to refs/heads/master by this push:
new 368c769 "CAMEL-15274:camel-spring-boot - Add back http endpoint for route information"
368c769 is described below
commit 368c76981c3b189a6ef8a9959a8e2136898f6b39
Author: Kodanda Ramu Kakarla <kk...@kkakarla.pnq.csb>
AuthorDate: Sun Jul 19 14:54:04 2020 +0530
"CAMEL-15274:camel-spring-boot - Add back http endpoint for route information"
---
.../src/main/docs/spring-boot.adoc | 10 +-
.../endpoint/CamelRouteControllerEndpoint.java | 54 +++
...elRouteControllerEndpointAutoConfiguration.java | 42 ++
.../boot/actuate/endpoint/CamelRoutesEndpoint.java | 517 +++++++++++++++++++++
.../CamelRoutesEndpointAutoConfiguration.java | 52 +++
.../endpoint/CamelRoutesEndpointProperties.java | 45 ++
.../additional-spring-configuration-metadata.json | 28 ++
.../boot/actuate/endpoint/ActuatorTestRoute.java | 30 ++
.../CamelEndpointsGloballyEnabledTest.java | 48 ++
.../CamelRouteControllerEndpointEnabledTest.java | 55 +++
...erEndpointGloballyDisabledAndReenabledTest.java | 62 +++
.../endpoint/CamelRouteControllerEndpointTest.java | 62 +++
.../endpoint/CamelRoutesEndpointEnabledTest.java | 56 +++
.../actuate/endpoint/CamelRoutesEndpointTest.java | 85 ++++
.../CamelRoutesEndpointWriteOperationTest.java | 65 +++
15 files changed, 1210 insertions(+), 1 deletion(-)
diff --git a/core/camel-spring-boot/src/main/docs/spring-boot.adoc b/core/camel-spring-boot/src/main/docs/spring-boot.adoc
index 93d00c7..86fb065 100644
--- a/core/camel-spring-boot/src/main/docs/spring-boot.adoc
+++ b/core/camel-spring-boot/src/main/docs/spring-boot.adoc
@@ -92,7 +92,7 @@ When using spring-boot with Spring Boot make sure to use the following Maven dep
----
-The component supports 149 options, which are listed below.
+The component supports 157 options, which are listed below.
@@ -248,6 +248,14 @@ The component supports 149 options, which are listed below.
| *camel.threadpool.pool-size* | Sets the default core pool size (threads to keep minimum in pool) | | Integer
| *camel.threadpool.rejected-policy* | Sets the default handler for tasks which cannot be executed by the thread pool. | | ThreadPoolRejectedPolicy
| *camel.threadpool.time-unit* | Sets the default time unit used for keep alive time | | TimeUnit
+| *management.endpoint.camelroutecontroller.cache.time-to-live* | Maximum time that a response can be cached. | 0ms | Duration
+| *management.endpoint.camelroutecontroller.enabled* | To turn on or off information about Camel Route Controller via actuator endpoint. | true | Boolean
+| *management.endpoint.camelroutes.cache.time-to-live* | Maximum time that a response can be cached. | 0ms | Duration
+| *management.endpoint.camelroutes.enabled* | | false | Boolean
+| *management.endpoint.camelroutes.enabled* | Whether to enable the camelroutes endpoint. | true | Boolean
+| *management.endpoint.camelroutes.enabled* | To turn on or off information about Camel Routes via actuator endpoint. | true | Boolean
+| *management.endpoint.camelroutes.read-only* | Whether Camel Routes actuator is in read-only mode. If not in read-only mode then operations to start/stop routes would be enabled. | true | Boolean
+| *management.info.camel.enabled* | Whether to enable Camel info. | true | Boolean
|===
// spring-boot-auto-configure options: END
diff --git a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/actuate/endpoint/CamelRouteControllerEndpoint.java b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/actuate/endpoint/CamelRouteControllerEndpoint.java
new file mode 100644
index 0000000..c6d3f00
--- /dev/null
+++ b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/actuate/endpoint/CamelRouteControllerEndpoint.java
@@ -0,0 +1,54 @@
+/*
+ * 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.spring.boot.actuate.endpoint;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Route;
+import org.apache.camel.spi.RouteController;
+import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
+import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
+
+/*
+ * {@link Endpoint} to expose {@link RouteController} information.
+ */
+@Endpoint(id = "camelroutecontroller", enableByDefault = true)
+public class CamelRouteControllerEndpoint {
+
+ private CamelContext camelContext;
+
+ public CamelRouteControllerEndpoint(CamelContext camelContext) {
+ this.camelContext = camelContext;
+ }
+
+ @ReadOperation
+ public List<String> getControlledRoutes() {
+ RouteController controller = camelContext.getRouteController();
+
+ if (controller != null) {
+ return controller.getControlledRoutes().stream()
+ .map(Route::getId)
+ .collect(Collectors.toList());
+ }
+
+ return Collections.emptyList();
+ }
+
+}
diff --git a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/actuate/endpoint/CamelRouteControllerEndpointAutoConfiguration.java b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/actuate/endpoint/CamelRouteControllerEndpointAutoConfiguration.java
new file mode 100644
index 0000000..0b2cccd
--- /dev/null
+++ b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/actuate/endpoint/CamelRouteControllerEndpointAutoConfiguration.java
@@ -0,0 +1,42 @@
+/*
+ * 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.spring.boot.actuate.endpoint;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/*
+ * Auto configuration for the {@link CamelRouteControllerEndpoint}.
+ */
+@Configuration
+@ConditionalOnClass({CamelRouteControllerEndpoint.class})
+@ConditionalOnBean(CamelAutoConfiguration.class)
+@AutoConfigureAfter(CamelAutoConfiguration.class)
+public class CamelRouteControllerEndpointAutoConfiguration {
+ @Bean
+ @ConditionalOnClass(CamelContext.class)
+ @ConditionalOnMissingBean
+ public CamelRouteControllerEndpoint routeControllerEndpoint(CamelContext camelContext) {
+ return new CamelRouteControllerEndpoint(camelContext);
+ }
+}
diff --git a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/actuate/endpoint/CamelRoutesEndpoint.java b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/actuate/endpoint/CamelRoutesEndpoint.java
new file mode 100644
index 0000000..1b2c34c
--- /dev/null
+++ b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/actuate/endpoint/CamelRoutesEndpoint.java
@@ -0,0 +1,517 @@
+/*
+ * 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.spring.boot.actuate.endpoint;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.ExtendedCamelContext;
+import org.apache.camel.Route;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.StatefulService;
+import org.apache.camel.api.management.ManagedCamelContext;
+import org.apache.camel.api.management.mbean.ManagedRouteMBean;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.spi.RouteError;
+import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
+import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
+import org.springframework.boot.actuate.endpoint.annotation.Selector;
+import org.springframework.boot.actuate.endpoint.annotation.WriteOperation;
+import org.springframework.lang.Nullable;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+
+
+/*
+ * {@link Endpoint} to expose {@link org.apache.camel.Route} information.
+ */
+@Endpoint(id = "camelroutes", enableByDefault = true)
+public class CamelRoutesEndpoint {
+
+ private CamelContext camelContext;
+ private static ExtendedCamelContext extendedContext;
+ private static ManagedCamelContext mcontext;
+ private static DefaultCamelContext dcontext;
+ private CamelRoutesEndpointProperties properties;
+
+ public CamelRoutesEndpoint(CamelContext camelContext, CamelRoutesEndpointProperties properties) {
+ this.camelContext = camelContext;
+ this.extendedContext = camelContext.getExtension(ExtendedCamelContext.class);
+ this.mcontext = camelContext.getExtension(ManagedCamelContext.class);;
+ this.dcontext = camelContext.getExtension(DefaultCamelContext.class);
+ this.properties = properties;
+ }
+
+ @ReadOperation
+ public List<RouteEndpointInfo> readRoutes() {
+ return getRoutesInfo();
+ }
+
+ @ReadOperation
+ public Object doReadAction(@Selector String id, @Selector ReadAction action) {
+ switch (action) {
+ case DETAIL:
+ return getRouteDetailsInfo(id);
+ case INFO:
+ return getRouteInfo(id);
+ default:
+ throw new IllegalArgumentException("Unsupported read action " + action);
+ }
+ }
+
+ @WriteOperation
+ public void doWriteAction(@Selector String id, @Selector WriteAction action, @Nullable TimeInfo timeInfo) {
+ if (this.properties.isReadOnly()) {
+ throw new IllegalArgumentException(String.format("Read only: write action %s is not allowed", action));
+ }
+
+ switch (action) {
+ case STOP:
+ stopRoute(
+ id,
+ Optional.ofNullable(timeInfo).flatMap(ti -> Optional.ofNullable(ti.getTimeout())),
+ Optional.of(TimeUnit.SECONDS),
+ Optional.ofNullable(timeInfo).flatMap(ti -> Optional.ofNullable(ti.getAbortAfterTimeout())));
+ break;
+ case START:
+ startRoute(id);
+ break;
+ case RESET:
+ resetRoute(id);
+ break;
+ case SUSPEND:
+ suspendRoute(id,
+ Optional.ofNullable(timeInfo).flatMap(ti -> Optional.ofNullable(ti.getTimeout())),
+ Optional.of(TimeUnit.SECONDS));
+ break;
+ case RESUME:
+ resumeRoute(id);
+ break;
+ default:
+ throw new IllegalArgumentException("Unsupported write action " + action);
+ }
+ }
+
+ private RouteEndpointInfo getRouteInfo(String id) {
+ Route route = camelContext.getRoute(id);
+ if (route != null) {
+ return new RouteEndpointInfo(route);
+ }
+
+ return null;
+ }
+
+ private List<RouteEndpointInfo> getRoutesInfo() {
+ return camelContext.getRoutes().stream()
+ .map(RouteEndpointInfo::new)
+ .collect(Collectors.toList());
+ }
+
+ private RouteDetailsEndpointInfo getRouteDetailsInfo(String id) {
+ Route route = camelContext.getRoute(id);
+ if (route != null) {
+ return new RouteDetailsEndpointInfo(camelContext, route);
+ }
+
+ return null;
+ }
+
+ private void startRoute(String id) {
+ try {
+ camelContext.getRouteController().startRoute(id);
+ } catch (Exception e) {
+ throw new RuntimeCamelException(e);
+ }
+ }
+
+ private void resetRoute(String id) {
+ try {
+ ManagedRouteMBean managedRouteMBean = mcontext.getManagedRoute(id, ManagedRouteMBean.class);
+ if (managedRouteMBean != null) {
+ managedRouteMBean.reset(true);
+ }
+ } catch (Exception e) {
+ throw new RuntimeCamelException(e);
+ }
+ }
+
+ private void stopRoute(String id, Optional<Long> timeout, Optional<TimeUnit> timeUnit, Optional<Boolean> abortAfterTimeout) {
+ try {
+ if (timeout.isPresent()) {
+ camelContext.getRouteController().stopRoute(id, timeout.get(), timeUnit.orElse(TimeUnit.SECONDS), abortAfterTimeout.orElse(Boolean.TRUE));
+ } else {
+ camelContext.getRouteController().stopRoute(id);
+ }
+ } catch (Exception e) {
+ throw new RuntimeCamelException(e);
+ }
+ }
+
+ private void suspendRoute(String id, Optional<Long> timeout, Optional<TimeUnit> timeUnit) {
+ try {
+ if (timeout.isPresent()) {
+ camelContext.getRouteController().suspendRoute(id, timeout.get(), timeUnit.orElse(TimeUnit.SECONDS));
+ } else {
+ camelContext.getRouteController().suspendRoute(id);
+ }
+ } catch (Exception e) {
+ throw new RuntimeCamelException(e);
+ }
+ }
+
+ private void resumeRoute(String id) {
+ try {
+ camelContext.getRouteController().resumeRoute(id);
+ } catch (Exception e) {
+ throw new RuntimeCamelException(e);
+ }
+ }
+
+ /*
+ * Container for exposing {@link org.apache.camel.Route} information as JSON.
+ */
+ @JsonPropertyOrder({"id", "group", "description", "uptime", "uptimeMillis"})
+ @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ public static class RouteEndpointInfo {
+
+ private final String id;
+
+ private final String group;
+
+ private final Map<String, Object> properties;
+
+ private final String description;
+
+ private final String uptime;
+
+ private final long uptimeMillis;
+
+ private final String status;
+
+ public RouteEndpointInfo(Route route) {
+ this.id = route.getId();
+ this.group = route.getGroup();
+ this.description = route.getDescription();
+ this.uptime = route.getUptime();
+ this.uptimeMillis = route.getUptimeMillis();
+
+ if (route.getProperties() != null) {
+ this.properties = new HashMap<>(route.getProperties());
+ } else {
+ this.properties = Collections.emptyMap();
+ }
+
+ if (route instanceof StatefulService) {
+ this.status = ((StatefulService) route).getStatus().name();
+ } else {
+ this.status = null;
+ }
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public String getGroup() {
+ return group;
+ }
+
+ public Map<String, Object> getProperties() {
+ return properties;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public String getUptime() {
+ return uptime;
+ }
+
+ public long getUptimeMillis() {
+ return uptimeMillis;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+ }
+
+ /*
+ * Container for exposing {@link org.apache.camel.Route} information
+ * with route details as JSON. Route details are retrieved from JMX.
+ */
+ public static class RouteDetailsEndpointInfo extends RouteEndpointInfo {
+
+ @JsonProperty("details")
+ private RouteDetails routeDetails;
+
+ public RouteDetailsEndpointInfo(final CamelContext camelContext, final Route route) {
+ super(route);
+
+ if (camelContext.getManagementStrategy().getManagementAgent() != null) {
+ this.routeDetails = new RouteDetails(mcontext.getManagedRoute(route.getId(), ManagedRouteMBean.class));
+ }
+ }
+
+ @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ static class RouteDetails {
+
+ private long deltaProcessingTime;
+
+ private long exchangesInflight;
+
+ private long exchangesTotal;
+
+ private long externalRedeliveries;
+
+ private long failuresHandled;
+
+ private String firstExchangeCompletedExchangeId;
+
+ private Date firstExchangeCompletedTimestamp;
+
+ private String firstExchangeFailureExchangeId;
+
+ private Date firstExchangeFailureTimestamp;
+
+ private String lastExchangeCompletedExchangeId;
+
+ private Date lastExchangeCompletedTimestamp;
+
+ private String lastExchangeFailureExchangeId;
+
+ private Date lastExchangeFailureTimestamp;
+
+ private long lastProcessingTime;
+
+ private String load01;
+
+ private String load05;
+
+ private String load15;
+
+ private long maxProcessingTime;
+
+ private long meanProcessingTime;
+
+ private long minProcessingTime;
+
+ private Long oldestInflightDuration;
+
+ private String oldestInflightExchangeId;
+
+ private long redeliveries;
+
+ private long totalProcessingTime;
+
+ private RouteError lastError;
+
+ private boolean hasRouteController;
+
+ RouteDetails(ManagedRouteMBean managedRoute) {
+ try {
+ this.deltaProcessingTime = managedRoute.getDeltaProcessingTime();
+ this.exchangesInflight = managedRoute.getExchangesInflight();
+ this.exchangesTotal = managedRoute.getExchangesTotal();
+ this.externalRedeliveries = managedRoute.getExternalRedeliveries();
+ this.failuresHandled = managedRoute.getFailuresHandled();
+ this.firstExchangeCompletedExchangeId = managedRoute.getFirstExchangeCompletedExchangeId();
+ this.firstExchangeCompletedTimestamp = managedRoute.getFirstExchangeCompletedTimestamp();
+ this.firstExchangeFailureExchangeId = managedRoute.getFirstExchangeFailureExchangeId();
+ this.firstExchangeFailureTimestamp = managedRoute.getFirstExchangeFailureTimestamp();
+ this.lastExchangeCompletedExchangeId = managedRoute.getLastExchangeCompletedExchangeId();
+ this.lastExchangeCompletedTimestamp = managedRoute.getLastExchangeCompletedTimestamp();
+ this.lastExchangeFailureExchangeId = managedRoute.getLastExchangeFailureExchangeId();
+ this.lastExchangeFailureTimestamp = managedRoute.getLastExchangeFailureTimestamp();
+ this.lastProcessingTime = managedRoute.getLastProcessingTime();
+ this.load01 = managedRoute.getLoad01();
+ this.load05 = managedRoute.getLoad05();
+ this.load15 = managedRoute.getLoad15();
+ this.maxProcessingTime = managedRoute.getMaxProcessingTime();
+ this.meanProcessingTime = managedRoute.getMeanProcessingTime();
+ this.minProcessingTime = managedRoute.getMinProcessingTime();
+ this.oldestInflightDuration = managedRoute.getOldestInflightDuration();
+ this.oldestInflightExchangeId = managedRoute.getOldestInflightExchangeId();
+ this.redeliveries = managedRoute.getRedeliveries();
+ this.totalProcessingTime = managedRoute.getTotalProcessingTime();
+ //this.lastError = managedRoute.getLastError();
+ this.hasRouteController = managedRoute.getHasRouteController();
+ } catch (Exception e) {
+ // Ignore
+ }
+ }
+
+ public long getDeltaProcessingTime() {
+ return deltaProcessingTime;
+ }
+
+ public long getExchangesInflight() {
+ return exchangesInflight;
+ }
+
+ public long getExchangesTotal() {
+ return exchangesTotal;
+ }
+
+ public long getExternalRedeliveries() {
+ return externalRedeliveries;
+ }
+
+ public long getFailuresHandled() {
+ return failuresHandled;
+ }
+
+ public String getFirstExchangeCompletedExchangeId() {
+ return firstExchangeCompletedExchangeId;
+ }
+
+ public Date getFirstExchangeCompletedTimestamp() {
+ return firstExchangeCompletedTimestamp;
+ }
+
+ public String getFirstExchangeFailureExchangeId() {
+ return firstExchangeFailureExchangeId;
+ }
+
+ public Date getFirstExchangeFailureTimestamp() {
+ return firstExchangeFailureTimestamp;
+ }
+
+ public String getLastExchangeCompletedExchangeId() {
+ return lastExchangeCompletedExchangeId;
+ }
+
+ public Date getLastExchangeCompletedTimestamp() {
+ return lastExchangeCompletedTimestamp;
+ }
+
+ public String getLastExchangeFailureExchangeId() {
+ return lastExchangeFailureExchangeId;
+ }
+
+ public Date getLastExchangeFailureTimestamp() {
+ return lastExchangeFailureTimestamp;
+ }
+
+ public long getLastProcessingTime() {
+ return lastProcessingTime;
+ }
+
+ public String getLoad01() {
+ return load01;
+ }
+
+ public String getLoad05() {
+ return load05;
+ }
+
+ public String getLoad15() {
+ return load15;
+ }
+
+ public long getMaxProcessingTime() {
+ return maxProcessingTime;
+ }
+
+ public long getMeanProcessingTime() {
+ return meanProcessingTime;
+ }
+
+ public long getMinProcessingTime() {
+ return minProcessingTime;
+ }
+
+ public Long getOldestInflightDuration() {
+ return oldestInflightDuration;
+ }
+
+ public String getOldestInflightExchangeId() {
+ return oldestInflightExchangeId;
+ }
+
+ public long getRedeliveries() {
+ return redeliveries;
+ }
+
+ public long getTotalProcessingTime() {
+ return totalProcessingTime;
+ }
+
+ public RouteError getLastError() {
+ return lastError;
+ }
+
+ public boolean getHasRouteController() {
+ return hasRouteController;
+ }
+ }
+ }
+
+ /*
+ * List of write actions available for the endpoint
+ */
+ public enum WriteAction {
+ STOP,
+ START,
+ RESET,
+ SUSPEND,
+ RESUME
+ }
+
+ /*
+ * List of read actions available for the endpoint
+ */
+ public enum ReadAction {
+ DETAIL,
+ INFO
+ }
+
+ /*
+ * Optional time information for the actions
+ */
+ public static class TimeInfo {
+ private Long timeout;
+ private Boolean abortAfterTimeout;
+
+ public Long getTimeout() {
+ return timeout;
+ }
+
+ public void setTimeout(Long timeout) {
+ this.timeout = timeout;
+ }
+
+ public Boolean getAbortAfterTimeout() {
+ return abortAfterTimeout;
+ }
+
+ public void setAbortAfterTimeout(Boolean abortAfterTimeout) {
+ this.abortAfterTimeout = abortAfterTimeout;
+ }
+ }
+
+}
diff --git a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/actuate/endpoint/CamelRoutesEndpointAutoConfiguration.java b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/actuate/endpoint/CamelRoutesEndpointAutoConfiguration.java
new file mode 100644
index 0000000..24c9131
--- /dev/null
+++ b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/actuate/endpoint/CamelRoutesEndpointAutoConfiguration.java
@@ -0,0 +1,52 @@
+/*
+ * 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.spring.boot.actuate.endpoint;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/*
+ * Auto configuration for the {@link CamelRoutesEndpoint}.
+ */
+@Configuration
+@EnableConfigurationProperties({ CamelRoutesEndpointProperties.class })
+@ConditionalOnClass({CamelRoutesEndpoint.class})
+@ConditionalOnBean(CamelAutoConfiguration.class)
+@AutoConfigureAfter(CamelAutoConfiguration.class)
+public class CamelRoutesEndpointAutoConfiguration {
+
+ private CamelRoutesEndpointProperties properties;
+
+ public CamelRoutesEndpointAutoConfiguration(CamelRoutesEndpointProperties properties) {
+ this.properties = properties;
+ }
+
+ @Bean
+ @ConditionalOnClass(CamelContext.class)
+ @ConditionalOnMissingBean
+ public CamelRoutesEndpoint camelEndpoint(CamelContext camelContext) {
+ return new CamelRoutesEndpoint(camelContext, properties);
+ }
+
+}
diff --git a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/actuate/endpoint/CamelRoutesEndpointProperties.java b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/actuate/endpoint/CamelRoutesEndpointProperties.java
new file mode 100644
index 0000000..21d447b
--- /dev/null
+++ b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/actuate/endpoint/CamelRoutesEndpointProperties.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.spring.boot.actuate.endpoint;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+@ConfigurationProperties("management.endpoint.camelroutes")
+public class CamelRoutesEndpointProperties {
+
+ private boolean readOnly = true;
+ private boolean enabled = false;
+
+ public boolean isReadOnly() {
+ return readOnly;
+ }
+
+ public void setReadOnly(boolean readOnly) {
+ this.readOnly = readOnly;
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+
+
+}
diff --git a/core/camel-spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/core/camel-spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json
new file mode 100644
index 0000000..cf56bd1
--- /dev/null
+++ b/core/camel-spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json
@@ -0,0 +1,28 @@
+{
+ "properties": [
+ {
+ "name": "management.endpoint.camelroutes.read-only",
+ "type": "java.lang.Boolean",
+ "description": "Whether Camel Routes actuator is in read-only mode. If not in read-only mode then operations to start/stop routes would be enabled.",
+ "defaultValue": true
+ },
+ {
+ "name": "management.endpoint.camelroutes.enabled",
+ "type": "java.lang.Boolean",
+ "description": "To turn on or off information about Camel Routes via actuator endpoint.",
+ "defaultValue": true
+ },
+ {
+ "name": "management.endpoint.camelroutecontroller.enabled",
+ "type": "java.lang.Boolean",
+ "description": "To turn on or off information about Camel Route Controller via actuator endpoint.",
+ "defaultValue": true
+ },
+ {
+ "name": "management.info.camel.enabled",
+ "type": "java.lang.Boolean",
+ "description": "Whether to enable Camel info.",
+ "defaultValue": true
+ }
+ ]
+}
diff --git a/core/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/actuate/endpoint/ActuatorTestRoute.java b/core/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/actuate/endpoint/ActuatorTestRoute.java
new file mode 100644
index 0000000..b56f1bc
--- /dev/null
+++ b/core/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/actuate/endpoint/ActuatorTestRoute.java
@@ -0,0 +1,30 @@
+/*
+ * 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.spring.boot.actuate.endpoint;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ActuatorTestRoute extends RouteBuilder {
+
+ @Override
+ public void configure() throws Exception {
+ from("timer:foo").routeId("foo-route").routeGroup("foo-route-group").to("log:foo");
+ }
+
+}
diff --git a/core/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/actuate/endpoint/CamelEndpointsGloballyEnabledTest.java b/core/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/actuate/endpoint/CamelEndpointsGloballyEnabledTest.java
new file mode 100644
index 0000000..729714a
--- /dev/null
+++ b/core/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/actuate/endpoint/CamelEndpointsGloballyEnabledTest.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.spring.boot.actuate.endpoint;
+
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@DirtiesContext
+@RunWith(SpringRunner.class)
+@SpringBootTest(
+ classes = {CamelAutoConfiguration.class, CamelRouteControllerEndpointAutoConfiguration.class,
+ CamelRoutesEndpointAutoConfiguration.class},
+ properties = {"management.endpoints.web.exposure.include=*"})
+
+public class CamelEndpointsGloballyEnabledTest {
+ @Autowired
+ private CamelRouteControllerEndpoint routeControllerEndpoint;
+
+ @Autowired
+ private CamelRoutesEndpoint routesEndpoint;
+
+ @Test
+ public void testHealthCheckEndpointPresent() throws Exception {
+ Assert.assertNotNull(routeControllerEndpoint);
+ Assert.assertNotNull(routesEndpoint);
+ }
+}
diff --git a/core/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/actuate/endpoint/CamelRouteControllerEndpointEnabledTest.java b/core/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/actuate/endpoint/CamelRouteControllerEndpointEnabledTest.java
new file mode 100644
index 0000000..2a643e1
--- /dev/null
+++ b/core/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/actuate/endpoint/CamelRouteControllerEndpointEnabledTest.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.spring.boot.actuate.endpoint;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.junit4.SpringRunner;
+
+/*
+ * Test for the {@link CamelRoutesEndpoint} actuator endpoint.
+ */
+@DirtiesContext
+@RunWith(SpringRunner.class)
+@EnableAutoConfiguration
+@SpringBootApplication
+@SpringBootTest(
+ classes = {CamelAutoConfiguration.class, CamelRouteControllerEndpointAutoConfiguration.class, ActuatorTestRoute.class},
+ properties = {"management.endpoint.camelroutecontroller.enabled=true"}
+)
+public class CamelRouteControllerEndpointEnabledTest extends Assert {
+
+ @Autowired(required = true)
+ CamelRouteControllerEndpoint routeControllerEndpoint;
+
+ @Autowired
+ CamelContext camelContext;
+
+ @Test
+ public void testRoutesEndpointPresent() throws Exception {
+ Assert.assertNotNull(routeControllerEndpoint);
+ }
+
+}
diff --git a/core/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/actuate/endpoint/CamelRouteControllerEndpointGloballyDisabledAndReenabledTest.java b/core/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/actuate/endpoint/CamelRouteControllerEndpointGloballyDisabledAndReenabledTest.java
new file mode 100644
index 0000000..03e1e46
--- /dev/null
+++ b/core/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/actuate/endpoint/CamelRouteControllerEndpointGloballyDisabledAndReenabledTest.java
@@ -0,0 +1,62 @@
+/*
+ * 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.spring.boot.actuate.endpoint;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.junit4.SpringRunner;
+
+/*
+ * Test for the {@link CamelRoutesEndpoint} actuator endpoint.
+ */
+@DirtiesContext
+@RunWith(SpringRunner.class)
+@EnableAutoConfiguration
+@SpringBootApplication
+@SpringBootTest(
+ classes = {CamelAutoConfiguration.class, CamelRoutesEndpointAutoConfiguration.class,
+ CamelRouteControllerEndpointAutoConfiguration.class, ActuatorTestRoute.class},
+ properties = {"management.endpoints.enabled-by-default = true",
+ "management.endpoint.camelroutecontroller.enabled = true"}
+)
+public class CamelRouteControllerEndpointGloballyDisabledAndReenabledTest extends Assert {
+
+ @Autowired
+ CamelRouteControllerEndpoint routeControllerEndpoint;
+
+ @Autowired
+ CamelRoutesEndpoint routesEndpoint;
+
+ @Autowired
+ CamelContext camelContext;
+
+ @Test
+ public void testRoutesEndpointPresent() throws Exception {
+
+ Assert.assertNotNull(routesEndpoint);
+ Assert.assertNotNull(routeControllerEndpoint);
+ }
+
+}
diff --git a/core/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/actuate/endpoint/CamelRouteControllerEndpointTest.java b/core/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/actuate/endpoint/CamelRouteControllerEndpointTest.java
new file mode 100644
index 0000000..74cc589
--- /dev/null
+++ b/core/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/actuate/endpoint/CamelRouteControllerEndpointTest.java
@@ -0,0 +1,62 @@
+/*
+ * 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.spring.boot.actuate.endpoint;
+
+import java.util.List;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.junit4.SpringRunner;
+
+
+/*
+ * Test for the {@link CamelRouteControllerEndpoint} actuator endpoint.
+ */
+@DirtiesContext
+@RunWith(SpringRunner.class)
+@EnableAutoConfiguration
+@SpringBootApplication
+@SpringBootTest(classes = {CamelAutoConfiguration.class, CamelRouteControllerEndpointAutoConfiguration.class, ActuatorTestRoute.class})
+public class CamelRouteControllerEndpointTest extends Assert {
+
+ @Autowired
+ CamelRouteControllerEndpoint endpoint;
+
+ @Autowired
+ CamelContext camelContext;
+
+ @Test
+ public void testRouteControllerEndpoint() throws Exception {
+ List<String> routesId = endpoint.getControlledRoutes();
+
+ assertNotNull(routesId);
+ /* FIXME DefaultRouteController returns empty list while it does control any route...
+ assertFalse(routesId.isEmpty());
+ assertEquals(routesId.size(), camelContext.getRoutes().size());
+ assertTrue(routesId.stream().anyMatch(r -> "foo-route".equals(r)));
+ */
+ }
+
+}
diff --git a/core/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/actuate/endpoint/CamelRoutesEndpointEnabledTest.java b/core/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/actuate/endpoint/CamelRoutesEndpointEnabledTest.java
new file mode 100644
index 0000000..65a5f58
--- /dev/null
+++ b/core/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/actuate/endpoint/CamelRoutesEndpointEnabledTest.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.spring.boot.actuate.endpoint;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.junit4.SpringRunner;
+
+
+/*
+ * Test for the {@link CamelRoutesEndpoint} actuator endpoint.
+ */
+@DirtiesContext
+@RunWith(SpringRunner.class)
+@EnableAutoConfiguration
+@SpringBootApplication
+@SpringBootTest(
+ classes = {CamelAutoConfiguration.class, CamelRoutesEndpointAutoConfiguration.class, ActuatorTestRoute.class},
+ properties = {"management.endpoint.camelroutes.enabled = true"}
+)
+public class CamelRoutesEndpointEnabledTest extends Assert {
+
+ @Autowired
+ CamelRoutesEndpoint routesEndpoint;
+
+ @Autowired
+ CamelContext camelContext;
+
+ @Test
+ public void testRoutesEndpointNotPresent() throws Exception {
+ Assert.assertNotNull(routesEndpoint);
+ }
+
+}
diff --git a/core/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/actuate/endpoint/CamelRoutesEndpointTest.java b/core/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/actuate/endpoint/CamelRoutesEndpointTest.java
new file mode 100644
index 0000000..8b8aeca
--- /dev/null
+++ b/core/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/actuate/endpoint/CamelRoutesEndpointTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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.spring.boot.actuate.endpoint;
+
+import java.util.List;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.apache.camel.spring.boot.actuate.endpoint.CamelRoutesEndpoint.ReadAction;
+import org.apache.camel.spring.boot.actuate.endpoint.CamelRoutesEndpoint.RouteDetailsEndpointInfo;
+import org.apache.camel.spring.boot.actuate.endpoint.CamelRoutesEndpoint.RouteEndpointInfo;
+import org.apache.camel.spring.boot.actuate.endpoint.CamelRoutesEndpoint.TimeInfo;
+import org.apache.camel.spring.boot.actuate.endpoint.CamelRoutesEndpoint.WriteAction;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.junit4.SpringRunner;
+
+/*
+ * Test for the {@link CamelRoutesEndpoint} actuator endpoint.
+ */
+@DirtiesContext
+@RunWith(SpringRunner.class)
+@EnableAutoConfiguration
+@SpringBootApplication
+@SpringBootTest(classes = {CamelAutoConfiguration.class, CamelRoutesEndpointAutoConfiguration.class, ActuatorTestRoute.class},
+ properties = {"management.endpoints.web.exposure.include=*"})
+
+public class CamelRoutesEndpointTest extends Assert {
+
+ @Autowired
+ CamelRoutesEndpoint endpoint;
+
+ @Autowired
+ CamelContext camelContext;
+
+ @Test
+ public void testRoutesEndpoint() throws Exception {
+ List<RouteEndpointInfo> routes = endpoint.readRoutes();
+
+ assertFalse(routes.isEmpty());
+ assertEquals(routes.size(), camelContext.getRoutes().size());
+ assertTrue(routes.stream().anyMatch(r -> "foo-route".equals(r.getId())));
+ assertTrue(routes.stream().anyMatch(r -> "foo-route-group".equals(r.getGroup())));
+ assertTrue(routes.stream().anyMatch(r -> r.getProperties().containsKey("key1") && "val1".equals(r.getProperties().get("key1"))));
+ assertTrue(routes.stream().anyMatch(r -> r.getProperties().containsKey("key2") && "val2".equals(r.getProperties().get("key2"))));
+ }
+
+ @Test
+ public void testReadOperation() throws Exception {
+ Object answer = endpoint.doReadAction("foo-route", ReadAction.INFO);
+ Assert.assertEquals(RouteEndpointInfo.class, answer.getClass());
+ Assert.assertEquals("foo-route", RouteEndpointInfo.class.cast(answer).getId());
+ answer = endpoint.doReadAction("foo-route", ReadAction.DETAIL);
+ Assert.assertEquals(RouteDetailsEndpointInfo.class, answer.getClass());
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testWriteOperationReadOnly() throws Exception {
+ TimeInfo timeInfo = new TimeInfo();
+ timeInfo.setAbortAfterTimeout(true);
+ timeInfo.setTimeout(5L);
+ endpoint.doWriteAction("foo-route", WriteAction.STOP, timeInfo);
+ }
+
+}
diff --git a/core/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/actuate/endpoint/CamelRoutesEndpointWriteOperationTest.java b/core/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/actuate/endpoint/CamelRoutesEndpointWriteOperationTest.java
new file mode 100644
index 0000000..e50df8c
--- /dev/null
+++ b/core/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/actuate/endpoint/CamelRoutesEndpointWriteOperationTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.spring.boot.actuate.endpoint;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.ServiceStatus;
+import org.apache.camel.impl.engine.AbstractCamelContext;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.apache.camel.spring.boot.actuate.endpoint.CamelRoutesEndpoint.TimeInfo;
+import org.apache.camel.spring.boot.actuate.endpoint.CamelRoutesEndpoint.WriteAction;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.junit4.SpringRunner;
+
+/*
+ * Test for the {@link CamelRoutesEndpoint} actuator endpoint.
+ */
+@DirtiesContext
+@RunWith(SpringRunner.class)
+@EnableAutoConfiguration
+@SpringBootApplication
+@SpringBootTest(
+ classes = {CamelAutoConfiguration.class, CamelRoutesEndpointAutoConfiguration.class, ActuatorTestRoute.class},
+ properties = {"management.endpoint.camelroutes.read-only = false"})
+public class CamelRoutesEndpointWriteOperationTest extends Assert {
+
+ @Autowired
+ CamelRoutesEndpoint endpoint;
+
+ @Autowired
+ CamelContext camelContext;
+
+ @Test
+ public void testWriteOperation() throws Exception {
+ AbstractCamelContext acontext = camelContext.getExtension(AbstractCamelContext.class);
+ ServiceStatus status = acontext.getRouteStatus("foo-route");
+ Assert.assertTrue(status.isStarted());
+ TimeInfo timeInfo = new TimeInfo();
+ timeInfo.setAbortAfterTimeout(true);
+ timeInfo.setTimeout(10L);
+ endpoint.doWriteAction("foo-route", WriteAction.STOP, timeInfo);
+ status = acontext.getRouteStatus("foo-route");
+ Assert.assertTrue(status.isStopped());
+ }
+}