From 9ab6779dc2ae3650298cdec4df179b51f99430d5 Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Thu, 24 Jan 2019 11:55:46 -0500 Subject: [PATCH] Fix new Sonar smell and some other in JMX module (#2716) * Fix new Sonar smell and some other in JMX module * * Fix issues after testing --- .../dsl/IntegrationComponentSpec.java | 20 +- .../jmx/DefaultMBeanObjectConverter.java | 180 +++++----- .../jmx/DefaultNotificationMapper.java | 19 +- .../NotificationPublishingMessageHandler.java | 21 +- .../jmx/OperationInvokingMessageHandler.java | 41 ++- .../jmx/config/MBeanExporterParser.java | 20 +- .../monitor/IntegrationMBeanExporter.java | 326 ++++++++++-------- 7 files changed, 350 insertions(+), 277 deletions(-) diff --git a/spring-integration-core/src/main/java/org/springframework/integration/dsl/IntegrationComponentSpec.java b/spring-integration-core/src/main/java/org/springframework/integration/dsl/IntegrationComponentSpec.java index 059d589db4..886e66fb49 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/dsl/IntegrationComponentSpec.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/dsl/IntegrationComponentSpec.java @@ -79,18 +79,28 @@ public abstract class IntegrationComponentSpec attributeMap = new HashMap(); + Map attributeMap = new HashMap<>(); try { ObjectName objName = instance.getObjectName(); @@ -81,8 +86,8 @@ public class DefaultMBeanObjectConverter implements MBeanObjectConverter { // N.B. standard MemoryUsage MBeans will throw an exception when some // measurement is unsupported. Logging at trace rather than debug to // avoid confusion. - if (log.isTraceEnabled()) { - log.trace("Error getting attribute '" + attrInfo.getName() + "' on '" + objName + "'", e); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Error getting attribute '" + attrInfo.getName() + "' on '" + objName + "'", e); } // try to unwrap the exception somewhat; not sure this is ideal @@ -104,90 +109,95 @@ public class DefaultMBeanObjectConverter implements MBeanObjectConverter { return attributeMap; } - /** - * @param input - * @return recursively mapped object - */ private Object checkAndConvert(Object input) { - if (input == null) { - return input; - } - else if (input.getClass().isArray()) { - - if (CompositeData.class.isAssignableFrom(input.getClass().getComponentType())) { - List converted = new ArrayList(); - int length = Array.getLength(input); - for (int i = 0; i < length; i++) { - Object value = checkAndConvert(Array.get(input, i)); - converted.add(value); - } - return converted; - } - if (TabularData.class.isAssignableFrom(input.getClass().getComponentType())) { - // TODO haven't hit this yet, but expect to - log.warn("TabularData.isAssignableFrom(getComponentType) for " + input.toString()); - } - } - else if (input instanceof CompositeData) { - CompositeData data = (CompositeData) input; - - if (data.getCompositeType().isArray()) { - // TODO? I haven't found an example where this gets thrown - but need to test it on Tomcat/Jetty or - // something - log.warn("(data.getCompositeType().isArray for " + input.toString()); - } - else { - Map returnable = new HashMap(); - Set keys = data.getCompositeType().keySet(); - for (String key : keys) { - // we don't need to repeat name of this as an attribute - if ("ObjectName".equals(key)) { - continue; - } - Object value = checkAndConvert(data.get(key)); - returnable.put(key, value); - } - return returnable; - } + Object converted = null; + if (input instanceof CompositeData) { + converted = convertFromCompositeData((CompositeData) input); } else if (input instanceof TabularData) { - TabularData data = (TabularData) input; - - if (data.getTabularType().isArray()) { - // TODO? I haven't found an example where this gets thrown, so might not be required - log.warn("TabularData.isArray for " + input.toString()); - } - else { - - Map returnable = new HashMap(); - @SuppressWarnings("unchecked") - Set> keySet = (Set>) data.keySet(); - for (List keys : keySet) { - CompositeData cd = data.get(keys.toArray()); - Object value = checkAndConvert(cd); - - if (keys.size() == 1 && (value instanceof Map) && ((Map) value).size() == 2) { - - Object actualKey = keys.get(0); - Map valueMap = (Map) value; - - if (valueMap.containsKey("key") && valueMap.containsKey("value") - && actualKey.equals(valueMap.get("key"))) { - returnable.put(valueMap.get("key"), valueMap.get("value")); - } - else { - returnable.put(actualKey, value); - } - } - else { - returnable.put(keys, value); - } - } - - return returnable; - } + converted = convertFromTabularData((TabularData) input); + } + else if (input != null && input.getClass().isArray()) { + converted = convertFromArray(input); } - return input; + if (converted != null) { + return converted; + } + else { + return input; + } } + + private Object convertFromArray(Object input) { + if (CompositeData.class.isAssignableFrom(input.getClass().getComponentType())) { + List converted = new ArrayList<>(); + int length = Array.getLength(input); + for (int i = 0; i < length; i++) { + Object value = checkAndConvert(Array.get(input, i)); + converted.add(value); + } + return converted; + } + if (TabularData.class.isAssignableFrom(input.getClass().getComponentType())) { + // TODO haven't hit this yet, but expect to + LOGGER.warn("TabularData.isAssignableFrom(getComponentType) for " + input.toString()); + } + return null; + } + + private Object convertFromCompositeData(CompositeData data) { + if (data.getCompositeType().isArray()) { + // TODO? I haven't found an example where this gets thrown - but need to test it on Tomcat/Jetty or + // something + LOGGER.warn("(data.getCompositeType().isArray for " + data.toString()); + return null; + } + else { + Map returnable = new HashMap<>(); + Set keys = data.getCompositeType().keySet(); + for (String key : keys) { + // we don't need to repeat name of this as an attribute + if ("ObjectName".equals(key)) { + continue; + } + Object value = checkAndConvert(data.get(key)); + returnable.put(key, value); + } + return returnable; + } + } + + private Object convertFromTabularData(TabularData data) { + if (data.getTabularType().isArray()) { + // TODO? I haven't found an example where this gets thrown, so might not be required + LOGGER.warn("TabularData.isArray for " + data.toString()); + return null; + } + else { + Map returnable = new HashMap<>(); + @SuppressWarnings("unchecked") + Set> keySet = (Set>) data.keySet(); + for (List keys : keySet) { + CompositeData cd = data.get(keys.toArray()); + Object value = checkAndConvert(cd); + if (keys.size() == 1 && (value instanceof Map) && ((Map) value).size() == 2) { + Object actualKey = keys.get(0); + Map valueMap = (Map) value; + if (valueMap.containsKey("key") && valueMap.containsKey("value") + && actualKey.equals(valueMap.get("key"))) { + returnable.put(valueMap.get("key"), valueMap.get("value")); + } + else { + returnable.put(actualKey, value); + } + } + else { + returnable.put(keys, value); + } + } + return returnable; + } + } + } diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/DefaultNotificationMapper.java b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/DefaultNotificationMapper.java index cbf2a451cc..8590e82bd3 100644 --- a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/DefaultNotificationMapper.java +++ b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/DefaultNotificationMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2019 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. @@ -22,6 +22,7 @@ import javax.management.Notification; import javax.management.ObjectName; import org.springframework.integration.mapping.OutboundMessageMapper; +import org.springframework.lang.Nullable; import org.springframework.messaging.Message; import org.springframework.util.Assert; @@ -32,32 +33,34 @@ import org.springframework.util.Assert; * 'userData' of the Notification instance. * * @author Mark Fisher + * @author Artem Bilan + * * @since 2.0 */ class DefaultNotificationMapper implements OutboundMessageMapper { private final ObjectName sourceObjectName; + @Nullable private final String defaultNotificationType; private final AtomicLong sequence = new AtomicLong(); - DefaultNotificationMapper(ObjectName sourceObjectName, String defaultNotificationType) { + DefaultNotificationMapper(ObjectName sourceObjectName, @Nullable String defaultNotificationType) { this.sourceObjectName = sourceObjectName; this.defaultNotificationType = defaultNotificationType; } - public Notification fromMessage(Message message) throws Exception { - String type = this.resolveNotificationType(message); - Assert.hasText(type, - "No notification type header is available, and no default has been provided."); - Object payload = (message != null) ? message.getPayload() : null; + public Notification fromMessage(Message message) { + String type = resolveNotificationType(message); + Assert.hasText(type, "No notification type header is available, and no default has been provided."); + Object payload = message.getPayload(); String notificationMessage = (payload instanceof String) ? (String) payload : null; Notification notification = new Notification(type, this.sourceObjectName, this.sequence.incrementAndGet(), System.currentTimeMillis(), notificationMessage); - if (payload != null && !(payload instanceof String)) { + if (!(payload instanceof String)) { notification.setUserData(payload); } return notification; diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/NotificationPublishingMessageHandler.java b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/NotificationPublishingMessageHandler.java index 9691bb08d5..1c1a113331 100644 --- a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/NotificationPublishingMessageHandler.java +++ b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/NotificationPublishingMessageHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 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. @@ -35,6 +35,7 @@ import org.springframework.jmx.export.annotation.ManagedResource; import org.springframework.jmx.export.notification.NotificationPublisher; import org.springframework.jmx.export.notification.NotificationPublisherAware; import org.springframework.jmx.support.ObjectNameManager; +import org.springframework.lang.Nullable; import org.springframework.messaging.Message; import org.springframework.util.Assert; @@ -55,11 +56,12 @@ public class NotificationPublishingMessageHandler extends AbstractMessageHandler private final PublisherDelegate delegate = new PublisherDelegate(); - private volatile OutboundMessageMapper notificationMapper; - private final ObjectName objectName; - private volatile String defaultNotificationType; + private String defaultNotificationType; + + @Nullable + private OutboundMessageMapper notificationMapper; public NotificationPublishingMessageHandler(ObjectName objectName) { @@ -85,7 +87,7 @@ public class NotificationPublishingMessageHandler extends AbstractMessageHandler * will be passed as the 'userData' of the Notification. * @param notificationMapper The notification mapper. */ - public void setNotificationMapper(OutboundMessageMapper notificationMapper) { + public void setNotificationMapper(@Nullable OutboundMessageMapper notificationMapper) { this.notificationMapper = notificationMapper; } @@ -108,8 +110,9 @@ public class NotificationPublishingMessageHandler extends AbstractMessageHandler @Override public final void onInit() { Assert.isTrue(this.getBeanFactory() instanceof ListableBeanFactory, "A ListableBeanFactory is required."); - Map exporters = BeanFactoryUtils.beansOfTypeIncludingAncestors( - (ListableBeanFactory) this.getBeanFactory(), MBeanExporter.class); + Map exporters = + BeanFactoryUtils.beansOfTypeIncludingAncestors((ListableBeanFactory) getBeanFactory(), + MBeanExporter.class); Assert.isTrue(exporters.size() > 0, "No MBeanExporter is available in the current context."); MBeanExporter exporter = null; for (MBeanExporter exp : exporters.values()) { @@ -128,7 +131,7 @@ public class NotificationPublishingMessageHandler extends AbstractMessageHandler } @Override - protected void handleMessageInternal(Message message) throws Exception { + protected void handleMessageInternal(Message message) throws Exception { // NOSONAR this.delegate.publish(this.notificationMapper.fromMessage(message)); } @@ -141,7 +144,7 @@ public class NotificationPublishingMessageHandler extends AbstractMessageHandler @IntegrationManagedResource public static class PublisherDelegate implements NotificationPublisherAware { - private volatile NotificationPublisher notificationPublisher; + private NotificationPublisher notificationPublisher; @Override public void setNotificationPublisher(NotificationPublisher notificationPublisher) { diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/OperationInvokingMessageHandler.java b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/OperationInvokingMessageHandler.java index dba76edbca..d93e27ef7c 100644 --- a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/OperationInvokingMessageHandler.java +++ b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/OperationInvokingMessageHandler.java @@ -191,25 +191,9 @@ public class OperationInvokingMessageHandler extends AbstractReplyProducingMessa hasNoArgOption = true; } if (paramInfoArray.length == paramsFromMessage.size()) { - int index = 0; Object[] values = new Object[paramInfoArray.length]; String[] signature = new String[paramInfoArray.length]; - for (MBeanParameterInfo paramInfo : paramInfoArray) { - Object value = paramsFromMessage.get(paramInfo.getName()); - if (value == null) { - /* - * With Spring 3.2.3 and greater, the parameter names are - * registered instead of the JVM's default p1, p2 etc. - * Fall back to that naming style if not found. - */ - value = paramsFromMessage.get("p" + (index + 1)); - } - if (value != null && valueTypeMatchesParameterType(value, paramInfo)) { - values[index] = value; - signature[index] = paramInfo.getType(); - index++; - } - } + int index = populateValuesAndSignature(paramsFromMessage, paramInfoArray, values, signature); if (index == paramInfoArray.length) { return this.server.invoke(objectName, operation, values, signature); } @@ -226,6 +210,29 @@ public class OperationInvokingMessageHandler extends AbstractReplyProducingMessa } } + private int populateValuesAndSignature(Map paramsFromMessage, MBeanParameterInfo[] paramInfoArray, + Object[] values, String[] signature) { + + int index = 0; + for (MBeanParameterInfo paramInfo : paramInfoArray) { + Object value = paramsFromMessage.get(paramInfo.getName()); + if (value == null) { + /* + * With Spring 3.2.3 and greater, the parameter names are + * registered instead of the JVM's default p1, p2 etc. + * Fall back to that naming style if not found. + */ + value = paramsFromMessage.get("p" + (index + 1)); + } + if (value != null && valueTypeMatchesParameterType(value, paramInfo)) { + values[index] = value; + signature[index] = paramInfo.getType(); + index++; + } + } + return index; + } + private boolean valueTypeMatchesParameterType(Object value, MBeanParameterInfo paramInfo) { Class valueClass = value.getClass(); if (valueClass.getName().equals(paramInfo.getType())) { diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/MBeanExporterParser.java b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/MBeanExporterParser.java index 52bdf302c6..0d464f84dd 100644 --- a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/MBeanExporterParser.java +++ b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/MBeanExporterParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2019 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. @@ -37,6 +37,8 @@ import org.springframework.util.StringUtils; * * @author Mark Fisher * @author Gary Russell + * @author Artem Bilan + * * @since 2.0 */ public class MBeanExporterParser extends AbstractSingleBeanDefinitionParser { @@ -56,17 +58,19 @@ public class MBeanExporterParser extends AbstractSingleBeanDefinitionParser { @Override protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { - Object mbeanServer = getMBeanServer(element, parserContext); + Object mbeanServer = getMBeanServer(element); builder.getRawBeanDefinition().setSource(parserContext.extractSource(element)); IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "default-domain"); IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "object-name-static-properties"); - IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "managed-components", "componentNamePatterns"); - IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "object-naming-strategy", "namingStrategy"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "managed-components", + "componentNamePatterns"); + IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "object-naming-strategy", + "namingStrategy"); builder.addPropertyValue("server", mbeanServer); } - private Object getMBeanServer(Element element, ParserContext parserContext) { + private Object getMBeanServer(Element element) { String mbeanServer = element.getAttribute("server"); if (StringUtils.hasText(mbeanServer)) { return new RuntimeBeanReference(mbeanServer); @@ -77,12 +81,14 @@ public class MBeanExporterParser extends AbstractSingleBeanDefinitionParser { } @Override - protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) throws BeanDefinitionStoreException { + protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) + throws BeanDefinitionStoreException { + String id = super.resolveId(element, definition, parserContext); if (MBEAN_EXPORTER_NAME.equals(id)) { parserContext.getReaderContext().error( "Illegal bean id for : " + MBEAN_EXPORTER_NAME + - " (clashes with default). Please choose another bean id.", + " (clashes with default). Please choose another bean id.", definition); } if (id.matches(IntegrationMBeanExporter.class.getName() + "#[0-9]+")) { diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/IntegrationMBeanExporter.java b/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/IntegrationMBeanExporter.java index cf34c5ea37..a92c237651 100644 --- a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/IntegrationMBeanExporter.java +++ b/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/IntegrationMBeanExporter.java @@ -34,9 +34,6 @@ import javax.management.JMException; import javax.management.ObjectName; import javax.management.modelmbean.ModelMBean; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - import org.springframework.aop.TargetSource; import org.springframework.aop.framework.Advised; import org.springframework.beans.BeansException; @@ -120,9 +117,9 @@ import org.springframework.util.StringValueResolver; public class IntegrationMBeanExporter extends MBeanExporter implements ApplicationContextAware, EmbeddedValueResolverAware, DestructionAwareBeanPostProcessor { - private static final Log logger = LogFactory.getLog(IntegrationMBeanExporter.class); + private static final String SI_PACKAGE = "org.springframework.integration"; - public static final String DEFAULT_DOMAIN = "org.springframework.integration"; + public static final String DEFAULT_DOMAIN = SI_PACKAGE; private final IntegrationJmxAttributeSource attributeSource = new IntegrationJmxAttributeSource(); @@ -227,48 +224,11 @@ public class IntegrationMBeanExporter extends MBeanExporter implements Applicati @Override public void afterSingletonsInstantiated() { - Map messageHandlers = - this.applicationContext.getBeansOfType(MessageHandlerMetrics.class); - for (Entry entry : messageHandlers.entrySet()) { - String beanName = entry.getKey(); - MessageHandlerMetrics bean = entry.getValue(); - if (this.handlerInAnonymousWrapper(bean) != null) { - if (logger.isDebugEnabled()) { - logger.debug("Skipping " + beanName + " because it wraps another handler"); - } - continue; - } - // If the handler is proxied, we have to extract the target to expose as an MBean. - // The MetadataMBeanInfoAssembler does not support JDK dynamic proxies. - MessageHandlerMetrics monitor = (MessageHandlerMetrics) extractTarget(bean); - this.handlers.add(monitor); - } + populateMessageHandlers(); + populateMessageSources(); + populateMessageChannels(); + populateMessageProducers(); - Map messageSources = - this.applicationContext.getBeansOfType(MessageSourceMetrics.class); - for (Entry entry : messageSources.entrySet()) { - // If the source is proxied, we have to extract the target to expose as an MBean. - // The MetadataMBeanInfoAssembler does not support JDK dynamic proxies. - MessageSourceMetrics monitor = (MessageSourceMetrics) extractTarget(entry.getValue()); - this.sources.add(monitor); - } - - Map messageChannels = - this.applicationContext.getBeansOfType(MessageChannelMetrics.class); - for (Entry entry : messageChannels.entrySet()) { - // If the channel is proxied, we have to extract the target to expose as an MBean. - // The MetadataMBeanInfoAssembler does not support JDK dynamic proxies. - MessageChannelMetrics monitor = (MessageChannelMetrics) extractTarget(entry.getValue()); - this.channels.add(monitor); - } - Map messageProducers = - this.applicationContext.getBeansOfType(MessageProducer.class); - for (Entry entry : messageProducers.entrySet()) { - MessageProducer messageProducer = entry.getValue(); - if (messageProducer instanceof Lifecycle) { - registerProducer(messageProducer); - } - } super.afterSingletonsInstantiated(); try { registerChannels(); @@ -285,19 +245,8 @@ public class IntegrationMBeanExporter extends MBeanExporter implements Applicati IntegrationContextUtils.INTEGRATION_MESSAGE_HISTORY_CONFIGURER_BEAN_NAME); } } - if (!this.applicationContext.containsBean(IntegrationManagementConfigurer.MANAGEMENT_CONFIGURER_NAME)) { - this.managementConfigurer = new IntegrationManagementConfigurer(); - this.managementConfigurer.setDefaultCountsEnabled(true); - this.managementConfigurer.setDefaultStatsEnabled(true); - this.managementConfigurer.setApplicationContext(this.applicationContext); - this.managementConfigurer.setBeanName(IntegrationManagementConfigurer.MANAGEMENT_CONFIGURER_NAME); - this.managementConfigurer.afterSingletonsInstantiated(); - } - else { - this.managementConfigurer = - this.applicationContext.getBean(IntegrationManagementConfigurer.MANAGEMENT_CONFIGURER_NAME, - IntegrationManagementConfigurer.class); - } + + configureManagementConfigurer(); this.singletonsInstantiated = true; } @@ -307,6 +256,71 @@ public class IntegrationMBeanExporter extends MBeanExporter implements Applicati } } + private void populateMessageHandlers() { + Map messageHandlers = + this.applicationContext.getBeansOfType(MessageHandlerMetrics.class); + for (Entry entry : messageHandlers.entrySet()) { + String beanName = entry.getKey(); + MessageHandlerMetrics bean = entry.getValue(); + if (this.handlerInAnonymousWrapper(bean) != null) { + if (logger.isDebugEnabled()) { + logger.debug("Skipping " + beanName + " because it wraps another handler"); + } + continue; + } + // If the handler is proxied, we have to extract the target to expose as an MBean. + // The MetadataMBeanInfoAssembler does not support JDK dynamic proxies. + MessageHandlerMetrics monitor = (MessageHandlerMetrics) extractTarget(bean); + this.handlers.add(monitor); + } + } + + private void populateMessageSources() { + this.applicationContext.getBeansOfType(MessageSourceMetrics.class) + .values() + .stream() + // If the channel is proxied, we have to extract the target to expose as an MBean. + // The MetadataMBeanInfoAssembler does not support JDK dynamic proxies. + .map(this::extractTarget) + .map(MessageSourceMetrics.class::cast) + .forEach(this.sources::add); + } + + private void populateMessageChannels() { + this.applicationContext.getBeansOfType(MessageChannelMetrics.class) + .values() + .stream() + // If the channel is proxied, we have to extract the target to expose as an MBean. + // The MetadataMBeanInfoAssembler does not support JDK dynamic proxies. + .map(this::extractTarget) + .map(MessageChannelMetrics.class::cast) + .forEach(this.channels::add); + } + + private void populateMessageProducers() { + this.applicationContext.getBeansOfType(MessageProducer.class) + .values() + .stream() + .filter(Lifecycle.class::isInstance) + .forEach(this::registerProducer); + } + + private void configureManagementConfigurer() { + if (!this.applicationContext.containsBean(IntegrationManagementConfigurer.MANAGEMENT_CONFIGURER_NAME)) { + this.managementConfigurer = new IntegrationManagementConfigurer(); + this.managementConfigurer.setDefaultCountsEnabled(true); + this.managementConfigurer.setDefaultStatsEnabled(true); + this.managementConfigurer.setApplicationContext(this.applicationContext); + this.managementConfigurer.setBeanName(IntegrationManagementConfigurer.MANAGEMENT_CONFIGURER_NAME); + this.managementConfigurer.afterSingletonsInstantiated(); + } + else { + this.managementConfigurer = + this.applicationContext.getBean(IntegrationManagementConfigurer.MANAGEMENT_CONFIGURER_NAME, + IntegrationManagementConfigurer.class); + } + } + @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (this.singletonsInstantiated) { @@ -322,33 +336,7 @@ public class IntegrationMBeanExporter extends MBeanExporter implements Applicati this.runtimeBeans.add(bean); } else if (bean instanceof AbstractEndpoint) { - if (bean instanceof IntegrationConsumer) { - IntegrationConsumer integrationConsumer = (IntegrationConsumer) bean; - MessageHandler handler = integrationConsumer.getHandler(); - if (handler instanceof MessageHandlerMetrics) { - MessageHandlerMetrics messageHandlerMetrics = - (MessageHandlerMetrics) extractTarget(handler); - registerHandler(messageHandlerMetrics); - this.handlers.add(messageHandlerMetrics); - this.runtimeBeans.add(messageHandlerMetrics); - return bean; - } - } - else if (bean instanceof SourcePollingChannelAdapter) { - SourcePollingChannelAdapter pollingChannelAdapter = (SourcePollingChannelAdapter) bean; - MessageSource messageSource = pollingChannelAdapter.getMessageSource(); - if (messageSource instanceof MessageSourceMetrics) { - MessageSourceMetrics messageSourceMetrics = - (MessageSourceMetrics) extractTarget(messageSource); - registerSource(messageSourceMetrics); - this.sources.add(messageSourceMetrics); - this.runtimeBeans.add(messageSourceMetrics); - return bean; - } - } - - registerEndpoint((AbstractEndpoint) bean); - this.runtimeBeans.add(bean); + postProcessAbstractEndpoint(bean); } } catch (Exception e) { @@ -358,6 +346,36 @@ public class IntegrationMBeanExporter extends MBeanExporter implements Applicati return bean; } + private void postProcessAbstractEndpoint(Object bean) { + if (bean instanceof IntegrationConsumer) { + IntegrationConsumer integrationConsumer = (IntegrationConsumer) bean; + MessageHandler handler = integrationConsumer.getHandler(); + if (handler instanceof MessageHandlerMetrics) { + MessageHandlerMetrics messageHandlerMetrics = + (MessageHandlerMetrics) extractTarget(handler); + registerHandler(messageHandlerMetrics); + this.handlers.add(messageHandlerMetrics); + this.runtimeBeans.add(messageHandlerMetrics); + return; + } + } + else if (bean instanceof SourcePollingChannelAdapter) { + SourcePollingChannelAdapter pollingChannelAdapter = (SourcePollingChannelAdapter) bean; + MessageSource messageSource = pollingChannelAdapter.getMessageSource(); + if (messageSource instanceof MessageSourceMetrics) { + MessageSourceMetrics messageSourceMetrics = + (MessageSourceMetrics) extractTarget(messageSource); + registerSource(messageSourceMetrics); + this.sources.add(messageSourceMetrics); + this.runtimeBeans.add(messageSourceMetrics); + return; + } + } + + registerEndpoint((AbstractEndpoint) bean); + this.runtimeBeans.add(bean); + } + private void registerProducer(MessageProducer messageProducer) { Lifecycle target = (Lifecycle) extractTarget(messageProducer); if (!(target instanceof AbstractMessageProducingHandler)) { @@ -367,7 +385,7 @@ public class IntegrationMBeanExporter extends MBeanExporter implements Applicati @Override public boolean requiresDestruction(Object bean) { - return bean instanceof MessageChannelMetrics || + return bean instanceof MessageChannelMetrics || // NOSONAR bean instanceof MessageHandlerMetrics || bean instanceof MessageSourceMetrics || (bean instanceof MessageProducer && bean instanceof Lifecycle) || @@ -803,7 +821,7 @@ public class IntegrationMBeanExporter extends MBeanExporter implements Applicati String beanKey; String name = endpoint.getComponentName(); String source; - if (name.startsWith("_org.springframework.integration")) { + if (name.startsWith('_' + SI_PACKAGE)) { name = getInternalComponentName(name); source = "internal"; } @@ -820,7 +838,7 @@ public class IntegrationMBeanExporter extends MBeanExporter implements Applicati name = unique; } this.endpointNames.add(name); - beanKey = getEndpointBeanKey(endpoint, name, source); + beanKey = getEndpointBeanKey(name, source); ObjectName objectName = registerBeanInstance(new ManagedEndpoint(endpoint), beanKey); this.objectNames.put(endpoint, objectName); if (logger.isInfoEnabled()) { @@ -857,7 +875,7 @@ public class IntegrationMBeanExporter extends MBeanExporter implements Applicati private String getChannelBeanKey(String channel) { String extra = ""; - if (channel.startsWith("org.springframework.integration")) { + if (channel.startsWith(SI_PACKAGE)) { extra = ",source=anonymous"; } return String.format(this.domain + ":type=MessageChannel,name=%s%s" + getStaticNames(), @@ -876,7 +894,7 @@ public class IntegrationMBeanExporter extends MBeanExporter implements Applicati quoteIfNecessary(source.getManagedName()), quoteIfNecessary(source.getManagedType())); } - private String getEndpointBeanKey(AbstractEndpoint endpoint, String name, String source) { + private String getEndpointBeanKey(String name, String source) { // This ordering of keys seems to work with default settings of JConsole return String.format(this.domain + ":type=ManagedEndpoint,name=%s,bean=%s" + getStaticNames(), quoteIfNecessary(name), source); @@ -908,7 +926,6 @@ public class IntegrationMBeanExporter extends MBeanExporter implements Applicati } private MessageHandlerMetrics enhanceHandlerMonitor(MessageHandlerMetrics monitor) { - MessageHandlerMetrics result = monitor; if (monitor.getManagedName() != null && monitor.getManagedType() != null) { @@ -927,8 +944,8 @@ public class IntegrationMBeanExporter extends MBeanExporter implements Applicati endpoint = this.applicationContext.getBean(beanName, IntegrationConsumer.class); try { MessageHandler handler = endpoint.getHandler(); - if (handler == monitor || - extractTarget(handlerInAnonymousWrapper(handler)) == monitor) { + if (handler.equals(monitor) || + extractTarget(handlerInAnonymousWrapper(handler)).equals(monitor)) { name = beanName; endpointName = beanName; break; @@ -939,11 +956,11 @@ public class IntegrationMBeanExporter extends MBeanExporter implements Applicati endpoint = null; } } - if (name != null && endpoint != null && name.startsWith("_org.springframework.integration")) { + if (name != null && name.startsWith('_' + SI_PACKAGE)) { name = getInternalComponentName(name); source = "internal"; } - if (name != null && endpoint != null && name.startsWith("org.springframework.integration")) { + if (name != null && name.startsWith(SI_PACKAGE)) { MessageChannel inputChannel = endpoint.getInputChannel(); if (inputChannel != null) { if (!this.anonymousHandlerCounters.containsKey(inputChannel)) { @@ -965,24 +982,7 @@ public class IntegrationMBeanExporter extends MBeanExporter implements Applicati } if (endpoint instanceof Lifecycle) { - // Wrap the monitor in a lifecycle so it exposes the start/stop operations - if (monitor instanceof MappingMessageRouterManagement) { - if (monitor instanceof TrackableComponent) { - result = new TrackableRouterMetrics((Lifecycle) endpoint, - (MappingMessageRouterManagement) monitor); - } - else { - result = new RouterMetrics((Lifecycle) endpoint, (MappingMessageRouterManagement) monitor); - } - } - else { - if (monitor instanceof TrackableComponent) { - result = new LifecycleTrackableMessageHandlerMetrics((Lifecycle) endpoint, monitor); - } - else { - result = new LifecycleMessageHandlerMetrics((Lifecycle) endpoint, monitor); - } - } + result = wrapMessageHandlerInLifecycleMetrics(monitor, (Lifecycle) endpoint); } if (name == null) { @@ -1006,8 +1006,35 @@ public class IntegrationMBeanExporter extends MBeanExporter implements Applicati } + /** + * Wrap the monitor in a lifecycle so it exposes the start/stop operations + */ + private MessageHandlerMetrics wrapMessageHandlerInLifecycleMetrics(MessageHandlerMetrics monitor, + Lifecycle endpoint) { + + MessageHandlerMetrics result; + if (monitor instanceof MappingMessageRouterManagement) { + if (monitor instanceof TrackableComponent) { + result = new TrackableRouterMetrics(endpoint, + (MappingMessageRouterManagement) monitor); + } + else { + result = new RouterMetrics(endpoint, (MappingMessageRouterManagement) monitor); + } + } + else { + if (monitor instanceof TrackableComponent) { + result = new LifecycleTrackableMessageHandlerMetrics(endpoint, monitor); + } + else { + result = new LifecycleMessageHandlerMetrics(endpoint, monitor); + } + } + return result; + } + private String getInternalComponentName(String name) { - return name.substring("_org.springframework.integration".length() + 1); + return name.substring(('_' + SI_PACKAGE).length() + 1); } private MessageSourceMetrics enhanceSourceMonitor(MessageSourceMetrics monitor) { @@ -1028,7 +1055,7 @@ public class IntegrationMBeanExporter extends MBeanExporter implements Applicati for (String beanName : names) { endpoint = this.applicationContext.getBean(beanName); Object field = null; - if (monitor instanceof MessagingGatewaySupport && endpoint == monitor) { + if (monitor instanceof MessagingGatewaySupport && endpoint.equals(monitor)) { field = monitor; } else { @@ -1041,30 +1068,29 @@ public class IntegrationMBeanExporter extends MBeanExporter implements Applicati } } - if (field == monitor) { + if (monitor.equals(field)) { name = beanName; endpointName = beanName; break; } } + if (endpointName == null) { endpoint = null; } - if (name != null && endpoint != null && name.startsWith("_org.springframework.integration")) { + if (name != null && name.startsWith('_' + SI_PACKAGE)) { name = getInternalComponentName(name); source = "internal"; } - if (name != null && endpoint != null && name.startsWith("org.springframework.integration")) { + if (name != null && name.startsWith(SI_PACKAGE)) { Object target = endpoint; if (endpoint instanceof Advised) { TargetSource targetSource = ((Advised) endpoint).getTargetSource(); - if (targetSource != null) { - try { - target = targetSource.getTarget(); - } - catch (Exception e) { - logger.error("Could not get handler from bean = " + name); - } + try { + target = targetSource.getTarget(); + } + catch (Exception e) { + logger.error("Could not get handler from bean = " + name); } } @@ -1096,25 +1122,7 @@ public class IntegrationMBeanExporter extends MBeanExporter implements Applicati } if (endpoint instanceof Lifecycle) { - // Wrap the monitor in a lifecycle so it exposes the start/stop operations - if (endpoint instanceof TrackableComponent) { - if (monitor instanceof MessageSourceManagement) { - result = new LifecycleTrackableMessageSourceManagement((Lifecycle) endpoint, - (MessageSourceManagement) monitor); - } - else { - result = new LifecycleTrackableMessageSourceMetrics((Lifecycle) endpoint, monitor); - } - } - else { - if (monitor instanceof MessageSourceManagement) { - result = new LifecycleMessageSourceManagement((Lifecycle) endpoint, - (MessageSourceManagement) monitor); - } - else { - result = new LifecycleMessageSourceMetrics((Lifecycle) endpoint, monitor); - } - } + result = wrapMessageSourceInLifecycleMetrics(monitor, endpoint); } if (name == null) { @@ -1132,7 +1140,33 @@ public class IntegrationMBeanExporter extends MBeanExporter implements Applicati return result; } - private static Object getField(Object target, String name) { + /** + * Wrap the monitor in a lifecycle so it exposes the start/stop operations + */ + private MessageSourceMetrics wrapMessageSourceInLifecycleMetrics(MessageSourceMetrics monitor, Object endpoint) { + MessageSourceMetrics result; + if (endpoint instanceof TrackableComponent) { + if (monitor instanceof MessageSourceManagement) { + result = new LifecycleTrackableMessageSourceManagement((Lifecycle) endpoint, + (MessageSourceManagement) monitor); + } + else { + result = new LifecycleTrackableMessageSourceMetrics((Lifecycle) endpoint, monitor); + } + } + else { + if (monitor instanceof MessageSourceManagement) { + result = new LifecycleMessageSourceManagement((Lifecycle) endpoint, + (MessageSourceManagement) monitor); + } + else { + result = new LifecycleMessageSourceMetrics((Lifecycle) endpoint, monitor); + } + } + return result; + } + + private Object getField(Object target, String name) { Assert.notNull(target, "Target object must not be null"); Field field = ReflectionUtils.findField(target.getClass(), name); if (field == null) {