diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/MBeanExporterHelper.java b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/MBeanExporterHelper.java new file mode 100644 index 0000000000..7ed7dc12c5 --- /dev/null +++ b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/MBeanExporterHelper.java @@ -0,0 +1,80 @@ +/* + * Copyright 2002-2011 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.integration.jmx.config; + +import java.util.HashSet; +import java.util.Set; + +import org.springframework.beans.BeansException; +import org.springframework.beans.DirectFieldAccessor; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.core.PriorityOrdered; +import org.springframework.integration.monitor.IntegrationMBeanExporter; +import org.springframework.jmx.export.MBeanExporter; + +/** + * Most likely a temporary class mainly needed to address issue described in INT-2307. + * It helps in eliminating conflicts when more than one MBeanExporter is present. It creates a list + * of bean names that will be exported by the IntegrationMBeanExporter and merges it with the list + * of 'excludedBeans' of MBeanExporter so it will not attempt to export them again. + * + * @author Oleg Zhurakousky + * @since 2.1 + * + */ +class MBeanExporterHelper implements BeanFactoryPostProcessor, BeanPostProcessor, PriorityOrdered { + + private final static String EXCLUDED_BEANS_PROPERTY_NAME = "excludedBeans"; + + private final static String SI_ROOT_PACKAGE = "org.springframework.integration."; + + private final Set siBeanNames = new HashSet(); + + @SuppressWarnings("unchecked") + public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { + if (bean instanceof MBeanExporter && !(bean instanceof IntegrationMBeanExporter)){ + MBeanExporter mbeanExporter = (MBeanExporter) bean; + DirectFieldAccessor mbeDfa = new DirectFieldAccessor(mbeanExporter); + Set excludedNames = (Set) mbeDfa.getPropertyValue(EXCLUDED_BEANS_PROPERTY_NAME); + if (excludedNames != null) { + siBeanNames.addAll(excludedNames); + } + mbeDfa.setPropertyValue(EXCLUDED_BEANS_PROPERTY_NAME, siBeanNames); + } + return bean; + } + + + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { + return bean; + } + + + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { + String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames(); + for (String beanName : beanDefinitionNames) { + BeanDefinition bd = beanFactory.getBeanDefinition(beanName); + String className = bd.getBeanClassName(); + if (className.startsWith(SI_ROOT_PACKAGE) && !(className.endsWith(IntegrationMBeanExporter.class.getName()))){ + siBeanNames.add(beanName); + } + } + } + + public int getOrder() { + return Integer.MIN_VALUE; + } +} 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 36ee82b3d2..1337250856 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 @@ -21,6 +21,8 @@ import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.integration.config.xml.IntegrationNamespaceUtils; @@ -56,8 +58,14 @@ public class MBeanExporterParser extends AbstractSingleBeanDefinitionParser { IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "managed-components", "componentNamePatterns"); builder.addPropertyValue("server", mbeanServer); + this.registerMBeanExporterHelper(parserContext.getRegistry()); } + private void registerMBeanExporterHelper(BeanDefinitionRegistry registry){ + BeanDefinitionBuilder mBeanExporterHelperBuilder = BeanDefinitionBuilder.rootBeanDefinition(MBeanExporterHelper.class); + BeanDefinitionReaderUtils.registerWithGeneratedName(mBeanExporterHelperBuilder.getBeanDefinition(), registry); + } + private Object getMBeanServer(Element element, ParserContext parserContext) { String mbeanServer = element.getAttribute("server"); if (StringUtils.hasText(mbeanServer)) { diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration_/mbeanexporterhelper/Int2307Tests.java b/spring-integration-jmx/src/test/java/org/springframework/integration_/mbeanexporterhelper/Int2307Tests.java new file mode 100644 index 0000000000..397bc40b8c --- /dev/null +++ b/spring-integration-jmx/src/test/java/org/springframework/integration_/mbeanexporterhelper/Int2307Tests.java @@ -0,0 +1,53 @@ +/* + * Copyright 2002-2011 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.integration_.mbeanexporterhelper; + +import java.util.Set; + +import org.junit.Test; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.integration.test.util.TestUtils; +import org.springframework.jmx.export.MBeanExporter; + +import static org.junit.Assert.assertTrue; + +/** + * @author Oleg Zhurakousky + * + */ +public class Int2307Tests { + + @Test + public void testInt2307_DefaultMBeanExporter() throws Exception{ + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("single-config.xml", this.getClass()); + context.destroy(); + } + + @SuppressWarnings("unchecked") + @Test + public void testInt2307_CustomMBeanExporter() throws Exception{ + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("single-config-custom-exporter.xml", this.getClass()); + MBeanExporter exporter = context.getBean("myExporter", MBeanExporter.class); + Set excludedBeanNames = TestUtils.getPropertyValue(exporter, "excludedBeans", Set.class); + assertTrue(excludedBeanNames.contains("rlr")); + assertTrue(excludedBeanNames.contains("hvr")); + assertTrue(excludedBeanNames.contains("x")); + assertTrue(excludedBeanNames.contains("y")); + assertTrue(excludedBeanNames.contains("foo")); // non SI bean + context.destroy(); + } + + public static class Foo{} +} diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration_/mbeanexporterhelper/single-config-custom-exporter.xml b/spring-integration-jmx/src/test/java/org/springframework/integration_/mbeanexporterhelper/single-config-custom-exporter.xml new file mode 100644 index 0000000000..670e34a37a --- /dev/null +++ b/spring-integration-jmx/src/test/java/org/springframework/integration_/mbeanexporterhelper/single-config-custom-exporter.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration_/mbeanexporterhelper/single-config.xml b/spring-integration-jmx/src/test/java/org/springframework/integration_/mbeanexporterhelper/single-config.xml new file mode 100644 index 0000000000..fffedc1c31 --- /dev/null +++ b/spring-integration-jmx/src/test/java/org/springframework/integration_/mbeanexporterhelper/single-config.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + +