Skip to content

Commit

Permalink
Shorten internal component names for graph (#3128)
Browse files Browse the repository at this point in the history
* Shorten internal component names for graph

The long `IntegrationContextUtils.ERROR_LOGGER_BEAN_NAME` name
is used for `errorChannel` `LoggingHandler`'s endpoint.
It is too long for endpoint node in the graph meanwhile the
`errorChannel` is good everywhere

* Change an `IntegrationGraphServer` logic to shorten internal
component names before drawing a graph
* Introduce `IntegrationUtils.obtainComponentName()` for
shortening an internal name if any
* Use `IntegrationConfigUtils.BASE_PACKAGE` in the `IntegrationMBeanExporter`
instead of its own static property
* Remove `IntegrationConfigUtils.FACTORY_BEAN_OBJECT_TYPE` in favor
of introduced in SF `FactoryBean.OBJECT_TYPE_ATTRIBUTE`
* Rework affected test classes to JUnit 5
* Remove usage of deprecated options in the `@EnableIntegrationManagement`
* Document names shortening feature for graph

* * Improve `obtainComponentName()` function
  • Loading branch information
artembilan committed Dec 26, 2019
1 parent c08f4ec commit fab7741
Show file tree
Hide file tree
Showing 9 changed files with 61 additions and 74 deletions.
Expand Up @@ -35,9 +35,6 @@ public final class IntegrationConfigUtils {

public static final String HANDLER_ALIAS_SUFFIX = ".handler";

// TODO: Boot constant - move to Spring Framework?
public static final String FACTORY_BEAN_OBJECT_TYPE = "factoryBeanObjectType";

public static void registerSpelFunctionBean(BeanDefinitionRegistry registry, String functionId, String className,
String methodSignature) {

Expand Down
Expand Up @@ -23,8 +23,8 @@
import java.util.Map.Entry;
import java.util.Set;

import org.springframework.beans.BeanMetadataAttribute;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
Expand Down Expand Up @@ -176,9 +176,7 @@ else if (StringUtils.hasText(asyncExecutor)) {
gatewayProxyBuilder.addConstructorArgValue(serviceInterface);

AbstractBeanDefinition beanDefinition = gatewayProxyBuilder.getBeanDefinition();
beanDefinition.addMetadataAttribute(new BeanMetadataAttribute(IntegrationConfigUtils.FACTORY_BEAN_OBJECT_TYPE,
serviceInterface));

beanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, serviceInterface);
return new BeanDefinitionHolder(beanDefinition, id);
}

Expand All @@ -188,7 +186,7 @@ else if (StringUtils.hasText(asyncExecutor)) {
* @param importingClassMetadata The importing class metadata
* @return The captured values.
*/
private static List<MultiValueMap<String, Object>> captureMetaAnnotationValues(
private static List<MultiValueMap<String, Object>> captureMetaAnnotationValues(
AnnotationMetadata importingClassMetadata) {

Set<String> directAnnotations = importingClassMetadata.getAnnotationTypes();
Expand Down
Expand Up @@ -48,6 +48,7 @@
import org.springframework.integration.router.RecipientListRouterManagement;
import org.springframework.integration.support.context.NamedComponent;
import org.springframework.integration.support.management.MappingMessageRouterManagement;
import org.springframework.integration.support.utils.IntegrationUtils;
import org.springframework.lang.Nullable;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;
Expand All @@ -65,7 +66,7 @@
*/
public class IntegrationGraphServer implements ApplicationContextAware, ApplicationListener<ContextRefreshedEvent> {

private static final float GRAPH_VERSION = 1.1f;
private static final float GRAPH_VERSION = 1.2f;

private static MicrometerNodeEnhancer micrometerEnhancer;

Expand Down Expand Up @@ -377,7 +378,7 @@ MessageGatewayNode gatewayNode(String name, MessagingGatewaySupport gateway) {
}

@Nullable
String channelToBeanName(MessageChannel messageChannel) {
private String channelToBeanName(MessageChannel messageChannel) {
return messageChannel instanceof NamedComponent
? ((NamedComponent) messageChannel).getBeanName()
: Objects.toString(messageChannel, null);
Expand All @@ -396,7 +397,7 @@ MessageSourceNode sourceNode(String name, SourcePollingChannelAdapter adapter) {
String nameToUse = name;
MessageSource<?> source = adapter.getMessageSource();
if (source instanceof NamedComponent) {
nameToUse = ((NamedComponent) source).getComponentName();
nameToUse = IntegrationUtils.obtainComponentName((NamedComponent) source);
}
MessageSourceNode node = new MessageSourceNode(this.nodeId.incrementAndGet(), nameToUse, source,
outputChannel, errorChannel);
Expand All @@ -412,7 +413,7 @@ MessageHandlerNode handlerNode(String nameArg, IntegrationConsumer consumer) {
MessageHandlerNode node;
String name = nameArg;
if (handler instanceof NamedComponent) {
name = ((NamedComponent) handler).getComponentName();
name = IntegrationUtils.obtainComponentName((NamedComponent) handler);
}
if (handler instanceof CompositeMessageHandler) {
node = compositeHandler(name, consumer, (CompositeMessageHandler) handler, outputChannelName, null,
Expand Down Expand Up @@ -448,7 +449,7 @@ MessageHandlerNode polledHandlerNode(String nameArg, PollingConsumer consumer) {
MessageHandlerNode node;
String name = nameArg;
if (handler instanceof NamedComponent) {
name = ((NamedComponent) handler).getComponentName();
name = IntegrationUtils.obtainComponentName((NamedComponent) handler);
}
if (handler instanceof CompositeMessageHandler) {
node = compositeHandler(name, consumer, (CompositeMessageHandler) handler, outputChannelName,
Expand Down Expand Up @@ -487,7 +488,7 @@ MessageHandlerNode compositeHandler(String name, IntegrationConsumer consumer,
.map(NamedComponent.class::cast)
.map(named ->
new CompositeMessageHandlerNode.InnerHandler(
named.getComponentName(),
IntegrationUtils.obtainComponentName(named),
named.getComponentType()))
.collect(Collectors.toList());

Expand Down
Expand Up @@ -24,8 +24,11 @@

import org.springframework.beans.factory.BeanFactory;
import org.springframework.core.convert.ConversionService;
import org.springframework.integration.config.IntegrationConfigUtils;
import org.springframework.integration.support.DefaultMessageBuilderFactory;
import org.springframework.integration.support.MessageBuilderFactory;
import org.springframework.integration.support.context.NamedComponent;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageDeliveryException;
import org.springframework.messaging.MessageHandlingException;
Expand All @@ -44,18 +47,19 @@
*/
public final class IntegrationUtils {

private static final Log logger = LogFactory.getLog(IntegrationUtils.class);
private static final Log LOGGER = LogFactory.getLog(IntegrationUtils.class);

private static final String INTERNAL_COMPONENT_PREFIX = '_' + IntegrationConfigUtils.BASE_PACKAGE;

public static final String INTEGRATION_CONVERSION_SERVICE_BEAN_NAME = "integrationConversionService";

public static final String INTEGRATION_MESSAGE_BUILDER_FACTORY_BEAN_NAME = "messageBuilderFactory";


/**
* Should be set to TRUE on CI plans and framework developer systems.
*/
public static final boolean fatalWhenNoBeanFactory =
Boolean.valueOf(System.getenv("SI_FATAL_WHEN_NO_BEANFACTORY"));
Boolean.parseBoolean(System.getenv("SI_FATAL_WHEN_NO_BEANFACTORY"));

private IntegrationUtils() {
super();
Expand All @@ -75,26 +79,24 @@ public static ConversionService getConversionService(BeanFactory beanFactory) {
* @param beanFactory The bean factory.
* @return The message builder factory.
*/
public static MessageBuilderFactory getMessageBuilderFactory(BeanFactory beanFactory) {
public static MessageBuilderFactory getMessageBuilderFactory(@Nullable BeanFactory beanFactory) {
MessageBuilderFactory messageBuilderFactory = null;
if (beanFactory != null) {
try {
messageBuilderFactory = beanFactory.getBean(
INTEGRATION_MESSAGE_BUILDER_FACTORY_BEAN_NAME, MessageBuilderFactory.class);
}
catch (Exception e) {
if (logger.isDebugEnabled()) {
logger.debug("No MessageBuilderFactory with name '"
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("No MessageBuilderFactory with name '"
+ INTEGRATION_MESSAGE_BUILDER_FACTORY_BEAN_NAME
+ "' found: " + e.getMessage()
+ ", using default.");
}
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("No 'beanFactory' supplied; cannot find MessageBuilderFactory, using default.");
}
LOGGER.debug("No 'beanFactory' supplied; cannot find MessageBuilderFactory, using default.");
if (fatalWhenNoBeanFactory) {
throw new IllegalStateException("All Message creators need a BeanFactory");
}
Expand Down Expand Up @@ -193,4 +195,18 @@ public static RuntimeException wrapInHandlingExceptionIfNecessary(Message<?> mes
return runtimeException;
}

/**
* Obtain a component name from the provided {@link NamedComponent}.
* @param component the {@link NamedComponent} source for component name.
* @return the component name
* @since 5.3
*/
public static String obtainComponentName(NamedComponent component) {
String name = component.getComponentName();
if (name.charAt(0) == '_' && name.startsWith(INTERNAL_COMPONENT_PREFIX)) {
name = name.substring((INTERNAL_COMPONENT_PREFIX).length() + 1);
}
return name;
}

}
Expand Up @@ -35,14 +35,14 @@

import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.expression.Expression;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.config.IntegrationConfigUtils;
import org.springframework.integration.gateway.GatewayMethodMetadata;
import org.springframework.integration.gateway.GatewayProxyFactoryBean;
import org.springframework.integration.gateway.RequestReplyExchanger;
Expand Down Expand Up @@ -177,16 +177,16 @@ public void testAsyncDisabledGateway() throws Exception {
@Test
public void testFactoryBeanObjectTypeWithServiceInterface() {
ConfigurableListableBeanFactory beanFactory = ((GenericApplicationContext) context).getBeanFactory();
Object attribute = beanFactory.getMergedBeanDefinition("&oneWay").getAttribute(
IntegrationConfigUtils.FACTORY_BEAN_OBJECT_TYPE);
Object attribute =
beanFactory.getMergedBeanDefinition("&oneWay").getAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE);
assertThat(attribute).isEqualTo(TestService.class.getName());
}

@Test
public void testFactoryBeanObjectTypeWithNoServiceInterface() {
ConfigurableListableBeanFactory beanFactory = ((GenericApplicationContext) context).getBeanFactory();
Object attribute = beanFactory.getMergedBeanDefinition("&defaultConfig").getAttribute(
IntegrationConfigUtils.FACTORY_BEAN_OBJECT_TYPE);
Object attribute =
beanFactory.getMergedBeanDefinition("&defaultConfig").getAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE);
assertThat(attribute).isEqualTo(RequestReplyExchanger.class.getName());
}

Expand Down
Expand Up @@ -24,9 +24,8 @@
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import org.hamcrest.Matchers;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ConfigurableApplicationContext;
Expand All @@ -43,8 +42,7 @@
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
Expand All @@ -62,8 +60,7 @@
*
* @since 4.3
*/
@RunWith(SpringRunner.class)
@WebAppConfiguration
@SpringJUnitWebConfig
@TestPropertySource(properties = "spring.application.name:testApplication")
@DirtiesContext
public class IntegrationGraphControllerTests {
Expand All @@ -73,7 +70,7 @@ public class IntegrationGraphControllerTests {

private MockMvc mockMvc;

@Before
@BeforeEach
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
Expand All @@ -88,8 +85,7 @@ public void testIntegrationGraphGet() throws Exception {
.andExpect(handler().handlerType(IntegrationGraphController.class))
.andExpect(handler().methodName("getGraph"))
.andExpect(jsonPath("$.nodes..name")
.value(Matchers.containsInAnyOrder("nullChannel", "errorChannel",
"_org.springframework.integration.errorLogger")))
.value(Matchers.containsInAnyOrder("nullChannel", "errorChannel", "errorLogger")))
// .andDo(print())
.andExpect(jsonPath("$.contentDescriptor.name").value("testApplication"))
.andExpect(jsonPath("$.links").exists());
Expand Down Expand Up @@ -154,9 +150,7 @@ public void testIntegrationGraphControllerParser() throws Exception {
@Configuration
@EnableWebMvc
@EnableIntegration
@EnableIntegrationManagement(statsEnabled = "_org.springframework.integration.errorLogger.handler",
countsEnabled = "!*",
defaultLoggingEnabled = "false")
@EnableIntegrationManagement(defaultLoggingEnabled = "false")
@EnableIntegrationGraphController(path = "/testIntegration", allowedOrigins = "https://foo.bar.com")
public static class ContextConfiguration {

Expand Down
Expand Up @@ -43,6 +43,7 @@
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.Lifecycle;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.config.IntegrationConfigUtils;
import org.springframework.integration.config.IntegrationManagementConfigurer;
import org.springframework.integration.context.IntegrationContextUtils;
import org.springframework.integration.context.OrderlyShutdownCapable;
Expand Down Expand Up @@ -111,9 +112,7 @@
public class IntegrationMBeanExporter extends MBeanExporter
implements ApplicationContextAware, DestructionAwareBeanPostProcessor {

private static final String SI_PACKAGE = "org.springframework.integration";

public static final String DEFAULT_DOMAIN = SI_PACKAGE;
public static final String DEFAULT_DOMAIN = IntegrationConfigUtils.BASE_PACKAGE;

private final IntegrationJmxAttributeSource attributeSource = new IntegrationJmxAttributeSource();

Expand Down Expand Up @@ -827,7 +826,7 @@ private void registerEndpoint(AbstractEndpoint endpoint) {
String beanKey;
String name = endpoint.getComponentName();
String source;
if (name.startsWith('_' + SI_PACKAGE)) {
if (name.startsWith('_' + IntegrationConfigUtils.BASE_PACKAGE)) {
name = getInternalComponentName(name);
source = "internal";
}
Expand Down Expand Up @@ -881,7 +880,7 @@ private Object extractTarget(Object bean) {

private String getChannelBeanKey(String channel) {
String extra = "";
if (channel.startsWith(SI_PACKAGE)) {
if (channel.startsWith(IntegrationConfigUtils.BASE_PACKAGE)) {
extra = ",source=anonymous";
}
return String.format(this.domain + ":type=MessageChannel,name=%s%s" + getStaticNames(),
Expand Down Expand Up @@ -979,11 +978,11 @@ private org.springframework.integration.support.management.MessageHandlerMetrics
String managedType = source;
String managedName = name;

if (managedName != null && managedName.startsWith('_' + SI_PACKAGE)) {
if (managedName != null && managedName.startsWith('_' + IntegrationConfigUtils.BASE_PACKAGE)) {
managedName = getInternalComponentName(managedName);
managedType = "internal";
}
if (managedName != null && name.startsWith(SI_PACKAGE)) {
if (managedName != null && name.startsWith(IntegrationConfigUtils.BASE_PACKAGE)) {
MessageChannel inputChannel = endpoint.getInputChannel();
if (inputChannel != null) {
managedName = buildAnonymousManagedName(this.anonymousHandlerCounters, inputChannel);
Expand Down Expand Up @@ -1058,7 +1057,7 @@ private String buildAnonymousManagedName(Map<Object, AtomicLong> anonymousCache,
}

private String getInternalComponentName(String name) {
return name.substring(('_' + SI_PACKAGE).length() + 1);
return name.substring(('_' + IntegrationConfigUtils.BASE_PACKAGE).length() + 1);
}

private org.springframework.integration.support.management.MessageSourceMetrics enhanceSourceMonitor(
Expand All @@ -1075,7 +1074,7 @@ private org.springframework.integration.support.management.MessageSourceMetrics
if (endpoint != null) {
endpointName = endpoint.getBeanName();
}
if (endpointName != null && endpointName.startsWith('_' + SI_PACKAGE)) {
if (endpointName != null && endpointName.startsWith('_' + IntegrationConfigUtils.BASE_PACKAGE)) {
endpointName = getInternalComponentName(endpointName);
source = "internal";
}
Expand Down Expand Up @@ -1115,7 +1114,7 @@ private org.springframework.integration.support.management.MessageSourceMetrics
String managedType = source;
String managedName = name;

if (managedName != null && managedName.startsWith(SI_PACKAGE)) {
if (managedName != null && managedName.startsWith(IntegrationConfigUtils.BASE_PACKAGE)) {
Object target = endpoint;
if (endpoint instanceof Advised) {
TargetSource targetSource = ((Advised) endpoint).getTargetSource();
Expand Down

0 comments on commit fab7741

Please sign in to comment.