Merge pull request #12331 from TYsewyn:feature/actuator-integration-graph

* pr/12331:
  Polish "Add actuator endpoint for exposing the Spring Integration graph"
  Add actuator endpoint for exposing the Spring Integration graph
pull/12972/head
Stephane Nicoll 7 years ago
commit af6bbca376

@ -0,0 +1,43 @@
[[integrationgraph]]
= Spring Integration graph (`integrationgraph`)
The `integrationgraph` endpoint exposes a graph containing all Spring Integration
components.
[[integrationgraph-retrieving]]
== Retrieving the Spring Integration graph
To retrieve the information about the application, make a `GET` request to
`/actuator/integrationgraph`, as shown in the following curl-based example:
include::{snippets}integrationgraph/graph/curl-request.adoc[]
The resulting response is similar to the following:
include::{snippets}integrationgraph/graph/http-response.adoc[]
[[integrationgraph-retrieving-response-structure]]
=== Response Structure
The response contains all Spring Integration components used within the application, as
well as the links between them. More information about the structure can be found in the
https://docs.spring.io/spring-integration/reference/html/system-management-chapter.html#integration-graph[reference
documentation].
[[integrationgraph-rebuilding]]
== Rebuilding the Spring Integration graph
To rebuild the exposed graph, make a `POST` request to `/actuator/integrationgraph`, as
shown in the following curl-based example:
include::{snippets}integrationgraph/rebuild/curl-request.adoc[]
This will result in a `204 - No Content` response:
include::{snippets}integrationgraph/rebuild/http-response.adoc[]

@ -59,6 +59,7 @@ include::endpoints/health.adoc[leveloffset=+1]
include::endpoints/heapdump.adoc[leveloffset=+1]
include::endpoints/httptrace.adoc[leveloffset=+1]
include::endpoints/info.adoc[leveloffset=+1]
include::endpoints/integrationgraph.adoc[leveloffset=+1]
include::endpoints/liquibase.adoc[leveloffset=+1]
include::endpoints/logfile.adoc[leveloffset=+1]
include::endpoints/loggers.adoc[leveloffset=+1]

@ -0,0 +1,61 @@
/*
* Copyright 2012-2018 the original author or authors.
*
* Licensed 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.springframework.boot.actuate.autoconfigure.integration;
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint;
import org.springframework.boot.actuate.integration.IntegrationGraphEndpoint;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
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.autoconfigure.integration.IntegrationAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.support.channel.HeaderChannelRegistry;
import org.springframework.integration.support.management.graph.IntegrationGraphServer;
/**
* {@link EnableAutoConfiguration Auto-configuration} for the {@link IntegrationGraphEndpoint}.
*
* @author Tim Ysewyn
* @author Stephane Nicoll
* @since 2.1.0
*/
@Configuration
@ConditionalOnClass(IntegrationGraphServer.class)
@ConditionalOnBean(HeaderChannelRegistry.class)
@AutoConfigureAfter(IntegrationAutoConfiguration.class)
public class IntegrationGraphEndpointAutoConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnEnabledEndpoint
public IntegrationGraphEndpoint integrationGraphEndpoint(
IntegrationGraphServer integrationGraphServer) {
return new IntegrationGraphEndpoint(integrationGraphServer);
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnEnabledEndpoint(endpoint = IntegrationGraphEndpoint.class)
public IntegrationGraphServer integrationGraphServer() {
return new IntegrationGraphServer();
}
}

@ -0,0 +1,20 @@
/*
* Copyright 2012-2018 the original author or authors.
*
* Licensed 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.
*/
/**
* Auto-configuration for actuator Spring Integration concerns.
*/
package org.springframework.boot.actuate.autoconfigure.integration;

@ -21,6 +21,7 @@ org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfigu
org.springframework.boot.actuate.autoconfigure.influx.InfluxDbHealthIndicatorAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.info.InfoContributorAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.integration.IntegrationGraphEndpointAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.jdbc.DataSourceHealthIndicatorAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.jms.JmsHealthIndicatorAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.jolokia.JolokiaEndpointAutoConfiguration,\

@ -0,0 +1,70 @@
/*
* Copyright 2012-2018 the original author or authors.
*
* Licensed 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.springframework.boot.actuate.autoconfigure.endpoint.web.documentation;
import org.junit.Test;
import org.springframework.boot.actuate.integration.IntegrationGraphEndpoint;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.integration.config.EnableIntegration;
import org.springframework.integration.support.management.graph.IntegrationGraphServer;
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* Tests for generating documentation describing the {@link IntegrationGraphEndpoint}.
*
* @author Tim Ysewyn
*/
public class IntegrationGraphEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {
@Test
public void graph() throws Exception {
this.mockMvc.perform(get("/actuator/integrationgraph")).andExpect(status().isOk())
.andDo(MockMvcRestDocumentation.document("integrationgraph/graph"));
}
@Test
public void rebuild() throws Exception {
this.mockMvc.perform(post("/actuator/integrationgraph")).andExpect(status()
.isNoContent())
.andDo(MockMvcRestDocumentation.document("integrationgraph/rebuild"));
}
@Configuration
@EnableIntegration
@Import(BaseDocumentationConfiguration.class)
static class TestConfiguration {
@Bean
public IntegrationGraphServer integrationGraphServer() {
return new IntegrationGraphServer();
}
@Bean
public IntegrationGraphEndpoint endpoint() {
return new IntegrationGraphEndpoint(integrationGraphServer());
}
}
}

@ -0,0 +1,70 @@
/*
* Copyright 2012-2018 the original author or authors.
*
* Licensed 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.springframework.boot.actuate.autoconfigure.integration;
import org.junit.Test;
import org.springframework.boot.actuate.integration.IntegrationGraphEndpoint;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration;
import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.integration.support.management.graph.IntegrationGraphServer;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link IntegrationGraphEndpointAutoConfiguration}.
*
* @author Tim Ysewyn
* @author Stephane Nicoll
*/
public class IntegrationGraphEndpointAutoConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(JmxAutoConfiguration.class,
IntegrationAutoConfiguration.class,
IntegrationGraphEndpointAutoConfiguration.class));
@Test
public void runShouldHaveEndpointBean() {
this.contextRunner.run((context) -> assertThat(context)
.hasSingleBean(IntegrationGraphEndpoint.class));
}
@Test
public void runWhenEnabledPropertyIsFalseShouldNotHaveEndpointBean() {
this.contextRunner
.withPropertyValues("management.endpoint.integrationgraph.enabled:false")
.run((context) -> {
assertThat(context).doesNotHaveBean(IntegrationGraphEndpoint.class);
assertThat(context).doesNotHaveBean(IntegrationGraphServer.class);
});
}
@Test
public void runWhenSpringIntegrationIsNotEnabledShouldNotHaveEndpointBean() {
ApplicationContextRunner noSiRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(
IntegrationGraphEndpointAutoConfiguration.class));
noSiRunner.run((context) -> {
assertThat(context).doesNotHaveBean(IntegrationGraphEndpoint.class);
assertThat(context).doesNotHaveBean(IntegrationGraphServer.class);
});
}
}

@ -0,0 +1,55 @@
/*
* Copyright 2012-2018 the original author or authors.
*
* Licensed 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.springframework.boot.actuate.integration;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.annotation.WriteOperation;
import org.springframework.integration.support.management.graph.Graph;
import org.springframework.integration.support.management.graph.IntegrationGraphServer;
/**
* {@link Endpoint} to expose the Spring Integration graph.
*
* @author Tim Ysewyn
* @since 2.1.0
*/
@Endpoint(id = "integrationgraph")
public class IntegrationGraphEndpoint {
private final IntegrationGraphServer graphServer;
/**
* Create a new {@code IntegrationGraphEndpoint} that exposes a graph containing all
* the Spring Integration components in the given {@link IntegrationGraphServer}.
* @param graphServer the integration graph server
*/
public IntegrationGraphEndpoint(IntegrationGraphServer graphServer) {
this.graphServer = graphServer;
}
@ReadOperation
public Graph graph() {
return this.graphServer.getGraph();
}
@WriteOperation
public void rebuild() {
this.graphServer.rebuild();
}
}

@ -0,0 +1,20 @@
/*
* Copyright 2012-2018 the original author or authors.
*
* Licensed 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.
*/
/**
* Actuator support for Spring Integration.
*/
package org.springframework.boot.actuate.integration;

@ -0,0 +1,67 @@
/*
* Copyright 2012-2018 the original author or authors.
*
* Licensed 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.springframework.boot.actuate.integration;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.integration.support.management.graph.Graph;
import org.springframework.integration.support.management.graph.IntegrationGraphServer;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.mock;
import static org.mockito.BDDMockito.verify;
import static org.mockito.BDDMockito.when;
/**
* Tests for {@link IntegrationGraphEndpoint}.
*
* @author Tim Ysewyn
*/
public class IntegrationGraphEndpointTests {
@Mock
private IntegrationGraphServer integrationGraphServer;
@InjectMocks
private IntegrationGraphEndpoint integrationGraphEndpoint;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
@Test
public void readOperationShouldReturnGraph() {
Graph mockedGraph = mock(Graph.class);
when(this.integrationGraphServer.getGraph()).thenReturn(mockedGraph);
Graph graph = this.integrationGraphEndpoint.graph();
verify(this.integrationGraphServer).getGraph();
assertThat(graph).isEqualTo(mockedGraph);
}
@Test
public void writeOperationShouldRebuildGraph() {
this.integrationGraphEndpoint.rebuild();
verify(this.integrationGraphServer).rebuild();
}
}

@ -0,0 +1,71 @@
/*
* Copyright 2012-2018 the original author or authors.
*
* Licensed 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.springframework.boot.actuate.integration;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.actuate.endpoint.web.test.WebEndpointRunners;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.integration.config.EnableIntegration;
import org.springframework.integration.support.management.graph.IntegrationGraphServer;
import org.springframework.test.web.reactive.server.WebTestClient;
/**
* Integration tests for {@link IntegrationGraphEndpoint} exposed by Jersey, Spring MVC, and WebFlux.
*
* @author Tim Ysewyn
*/
@RunWith(WebEndpointRunners.class)
public class IntegrationGraphEndpointWebIntegrationTests {
private static WebTestClient client;
@Test
public void graph() {
client.get().uri("/actuator/integrationgraph").accept(MediaType.APPLICATION_JSON).exchange()
.expectStatus().isOk().expectBody()
.jsonPath("contentDescriptor.providerVersion").isNotEmpty()
.jsonPath("contentDescriptor.providerFormatVersion").isEqualTo(1.0f)
.jsonPath("contentDescriptor.provider").isEqualTo("spring-integration");
}
@Test
public void rebuild() {
client.post().uri("/actuator/integrationgraph").accept(MediaType.APPLICATION_JSON).exchange()
.expectStatus().isNoContent();
}
@Configuration
@EnableIntegration
public static class TestConfiguration {
@Bean
public IntegrationGraphEndpoint endpoint(IntegrationGraphServer integrationGraphServer) {
return new IntegrationGraphEndpoint(integrationGraphServer);
}
@Bean
public IntegrationGraphServer integrationGraphServer() {
return new IntegrationGraphServer();
}
}
}

@ -105,6 +105,10 @@ exchanges).
|Displays arbitrary application info.
|Yes
|`integrationgraph`
|Shows the Spring Integration graph.
|Yes
|`loggers`
|Shows and modifies the configuration of loggers in the application.
|Yes
@ -252,6 +256,10 @@ endpoints:
|Yes
|Yes
|`integrationgraph`
|Yes
|Yes
|`jolokia`
|N/A
|No

Loading…
Cancel
Save