INT-4035, INT-4008: Docs for Integration Graph

JIRA: https://jira.spring.io/browse/INT-4035, https://jira.spring.io/browse/INT-4008

Polishing
This commit is contained in:
Artem Bilan
2016-05-23 20:08:11 -04:00
committed by Gary Russell
parent c6821ec387
commit d57db56a39
7 changed files with 232 additions and 6 deletions

View File

@@ -21,7 +21,6 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.integration.http.support.DefaultHttpHeaderMapper;
import org.springframework.integration.http.support.HttpContextUtils;
/**
@@ -30,7 +29,7 @@ import org.springframework.integration.http.support.HttpContextUtils;
*/
class IntegrationGraphControllerRegistrarImportSelector implements ImportSelector {
private static final Log logger = LogFactory.getLog(DefaultHttpHeaderMapper.class);
private static final Log logger = LogFactory.getLog(IntegrationGraphControllerRegistrarImportSelector.class);
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {

View File

@@ -10,8 +10,14 @@
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<mvc:annotation-driven/>
<mvc:annotation-driven />
<graph-controller path="/foo"/>
<mvc:cors>
<mvc:mapping path="/foo"
allowed-origins="http://foo.bar.com"
allowed-methods="GET" />
</mvc:cors>
<graph-controller path="/foo" />
</beans:beans>

View File

@@ -36,10 +36,13 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.config.EnableIntegration;
import org.springframework.integration.config.EnableIntegrationManagement;
import org.springframework.integration.http.config.EnableIntegrationGraphController;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
@@ -53,7 +56,9 @@ import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.HandlerAdapter;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
@@ -80,6 +85,7 @@ public class IntegrationGraphControllerTests {
@Test
public void testIntegrationGraphGet() throws Exception {
this.mockMvc.perform(get("/testIntegration")
.header(HttpHeaders.ORIGIN, "http://foo.bar.com")
.accept(MediaType.parseMediaType("application/json;charset=UTF-8")))
.andExpect(status().isOk())
.andExpect(content().contentType("application/json;charset=UTF-8"))
@@ -99,7 +105,6 @@ public class IntegrationGraphControllerTests {
"IntegrationGraphControllerParserTests-context.xml", getClass());
HandlerMapping handlerMapping =
context.getBean(RequestMappingHandlerMapping.class.getName(), HandlerMapping.class);
@@ -108,6 +113,7 @@ public class IntegrationGraphControllerTests {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("GET");
request.setRequestURI("/foo");
request.addHeader(HttpHeaders.ORIGIN, "http://foo.bar.com");
MockHttpServletResponse response = new MockHttpServletResponse();
HandlerExecutionChain executionChain = handlerMapping.getHandler(request);
@@ -142,8 +148,19 @@ public class IntegrationGraphControllerTests {
@Configuration
@EnableWebMvc
@EnableIntegration
@EnableIntegrationManagement(statsEnabled = "_org.springframework.integration.errorLogger.handler",
countsEnabled = "!*",
defaultLoggingEnabled = "false")
@EnableIntegrationGraphController(path = "/testIntegration")
public static class ContextConfiguration {
public static class ContextConfiguration extends WebMvcConfigurerAdapter {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/testIntegration/**")
.allowedOrigins("http://foo.bar.com")
.allowedMethods(HttpMethod.GET.name());
}
}

View File

@@ -0,0 +1,191 @@
[[integration-graph]]
=== Integration Graph
Starting with _version 4.3_, Spring Integration provides access to an application's runtime object model which can, optionally, include component metrics.
It is exposed as a graph, which may be used to visualize the current state of the integration application.
The `o.s.i.support.management.graph` package contains all the required classes to collect, build and render the runtime state of Spring Integration components as a single tree-like `Graph` object.
The `IntegrationGraphServer` should be declared as a bean to build, retrieve and refresh the `Graph` object.
The resulting `Graph` object can be serialized to any format, although JSON is flexible and convenient to parse and represent on the client side.
A simple Spring Integration application with only the default components would expose a graph as follows:
[source,json]
----
{
"contentDescriptor": {
"providerVersion": "4.3.0.RELEASE",
"providerFormatVersion": 1.0,
"provider": "spring-integration",
"name": "myApplication"
},
"nodes": [
{
"nodeId": 1,
"name": "nullChannel",
"stats": null,
"componentType": "channel"
},
{
"nodeId": 2,
"name": "errorChannel",
"stats": null,
"componentType": "publish-subscribe-channel"
},
{
"nodeId": 3,
"name": "_org.springframework.integration.errorLogger",
"stats": {
"duration": {
"count": 0,
"min": 0.0,
"max": 0.0,
"mean": 0.0,
"standardDeviation": 0.0,
"countLong": 0
},
"errorCount": 0,
"standardDeviationDuration": 0.0,
"countsEnabled": true,
"statsEnabled": true,
"loggingEnabled": false,
"handleCount": 0,
"meanDuration": 0.0,
"maxDuration": 0.0,
"minDuration": 0.0,
"activeCount": 0
},
"componentType": "logging-channel-adapter",
"output": null,
"input": "errorChannel"
}
],
"links": [
{
"from": 2,
"to": 3
}
]
}
----
As you can see, the graph consists of three top-level elements.
The `contentDescriptor` graph element is pretty straightforward and contains general information about the application providing the data.
The `name` can be customized on the `IntegrationGraphServer` bean or via `spring.application.name` application context environment property.
Other properties are provided by the framework and allows you to distinguish a similar model from other sources.
The `links` graph element represents connections between nodes from the `nodes` graph element and, therefore, between integration components in the source Spring Integration application.
For example _from_ a `MessageChannel` _to_ an `EventDrivenConsumer` with some `MessageHandler`;
or _from_ an `AbstractReplyProducingMessageHandler` _to_ a `MessageChannel`.
The information from this element can be used by a visualizing tool to render connections between nodes from the `nodes` graph element, where the `from` and `to` numbers represent the value from the `nodeId` property of the linked nodes.
The `nodes` graph element is perhaps the most interesting because its elements contain not only the runtime components with their `componentType` s and `name` s, but can also optionally contain metrics exposed by the component.
To enable the metrics, add an `@EnableIntegrationManagement` to some `@Configuration` class or add an `<int:management/>` element to your XML configuration.
You can control exactly which components in the framework collect statistics.
See <<metrics-management>> for complete information.
See the `stats` attribute from the `_org.springframework.integration.errorLogger` component in the JSON example above.
The `nullChannel` and `errorChannel` don't provide statistics information in this case, because the configuration for this example was:
[source,java]
----
@Configuration
@EnableIntegration
@EnableIntegrationManagement(statsEnabled = "_org.springframework.integration.errorLogger.handler",
countsEnabled = "!*",
defaultLoggingEnabled = "false")
public class ManagementConfiguration {
@Bean
public IntegrationGraphServer integrationGraphServer() {
return new IntegrationGraphServer();
}
}
----
The `nodeId` represents a unique incremental identifier to distinguish one component from another.
It is also used in the `links` element to represent a relationship (connection) of this component to others, if any.
The `input` and `output` attributes are for the `inputChannel` and `outputChannel` properties of the `AbstractEndpoint`, `MessageHandler`, `SourcePollingChannelAdapter` or `MessageProducerSupport`.
See the next paragraph for more information.
==== Graph Runtime Model
Spring Integration components have various levels of complexity.
For example, any polled `MessageSource` also has a `SourcePollingChannelAdapter` and a `MessageChannel` to which to send messages from the source data periodically.
Other components might be middleware request-reply components, e.g. `JmsOutboundGateway`, with a consuming `AbstractEndpoint` to subscribe to (or poll) the `requestChannel` (`input`) for messages, and a `replyChannel` (`output`) to produce a reply message to send downstream.
Meanwhile, any `MessageProducerSupport` implementation (e.g. `ApplicationEventListeningMessageProducer`) simply wraps some source protocol listening logic and sends messages to the `outputChannel`.
Within the graph, Spring Integration components are represented using the `IntegrationNode` class hierarchy, which you can find in the `o.s.i.support.management.graph` package.
For example the `ErrorCapableDiscardingMessageHandlerNode` could be used for the `AggregatingMessageHandler` (because it has a `discardChannel` option) and can produce errors when consuming from a `PollableChannel` using a `PollingConsumer`.
Another sample is `CompositeMessageHandlerNode` - for a `MessageHandlerChain` when subscribed to a `SubscribableChannel`, using an `EventDrivenConsumer`.
This `IntegrationNode` hierarchy can be used for parsing the graph model on the client side, as well as for the understanding the general Spring Integration runtime behavior.
See also <<programming-tips>> for more information.
=== Integration Graph Controller
If your application is WEB-based (or built on top of Spring Boot using an embedded web container) and the Spring Integration HTTP module (see <<http>>) is present on the classpath, you can use a `IntegrationGraphController` to expose the `IntegrationGraphServer` functionality as a REST service.
For this purpose, the `@EnableIntegrationGraphController` `@Configuration` class annotation and the `<int-http:graph-controller/>` XML element, are available in the HTTP module.
Together with the `@EnableWebMvc` annotation (or `<mvc:annotation-driven/>` for xml definitions), this configuration registers an `IntegrationGraphController` `@RestController` where its `@RequestMapping.path` can be configured on the `@EnableIntegrationGraphController` annotation or `<int-http:graph-controller/>` element.
The default path is `/integration`.
The `IntegrationGraphController` `@RestController` provides these services:
- `@GetMapping(name = "getGraph")` - to retrieve the state of the Spring Integration components since the last `IntegrationGraphServer` refresh.
The `o.s.i.support.management.graph.Graph` is returned as a `@ResponseBody` of the REST service;
- `@GetMapping(path = "/refresh", name = "refreshGraph")` - to refresh the current `Graph` for the actual runtime state and return it as a REST response.
It is not necessaery to refresh the graph for metrics, they are provided in real-time when the graph is retrieved.
Refresh can be called if the application context has been modified since the graph was last retrieved and the graph is completely rebuilt.
Any Security and Cross Origin restrictions for the `IntegrationGraphController` can be achieved with the standard configuration options and components provided by Spring Security and Spring MVC projects.
The simple example of that may be:
[source,xml]
----
<mvc:annotation-driven />
<mvc:cors>
<mvc:mapping path="/myIntegration/**"
allowed-origins="http://localhost:9090"
allowed-methods="GET" />
</mvc:cors>
<security:http>
<security:intercept-url pattern="/myIntegration/**" access="ROLE_ADMIN" />
</security:http>
<int-http:graph-controller path="/myIntegration" />
----
and the Java & Annotation Configuration variant is:
[source,java]
----
@Configuration
@EnableWebMvc
@EnableWebSecurity
@EnableIntegration
@EnableIntegrationGraphController(path = "/testIntegration")
public class IntegrationConfiguration extends WebSecurityConfigurerAdapter
implements WebMvcConfigurer {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/testIntegration/**").hasRole("ADMIN")
// ...
.formLogin();
}
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/testIntegration/**")
.allowedOrigins("http://localhost:9090")
.allowedMethods(HttpMethod.GET.name());
}
//...
}
----

View File

@@ -791,6 +791,12 @@ If further customization is required you can also configure a `DefaultHttpHeader
Of course, you can even implement the HeaderMapper strategy interface directly and provide a reference to that if you need to do something other than what the `DefaultHttpHeaderMapper` supports.
[[int-graph-controller]]
=== Integration Graph Controller
Starting with _version 4.3_, the HTTP module provides an `@EnableIntegrationGraphController` `@Configuration` class annotation and `<int-http:graph-controller/>` XML element to expose the `IntegrationGraphServer` as a REST service.
See <<integration-graph>> for more information.
[[http-samples]]
=== HTTP Samples

View File

@@ -15,4 +15,6 @@ include::./meta-data-store.adoc[]
include::./control-bus.adoc[]
include::./shutdown.adoc[]
include::./graph.adoc[]
// BE SURE TO PRECEDE ALL include:: with a blank line - see https://github.com/asciidoctor/asciidoctor/issues/1297

View File

@@ -38,6 +38,11 @@ See <<ftp-streaming>> and <<sftp-streaming>> for more information.
A new `StreamTransformer` is provided to transform an `InputStream` payload to either a `byte[]` or `String`.
See <<stream-transformer>> for more information.
==== Integration Graph
A new `IntegrationGraphServer` together with the `IntegrationGraphController` REST service are provided to expose the runtime model of a Spring Integration application as a graph.
See <<integration-graph>> for more information.
[[x4.3-general]]
=== General Changes