001/* 002 * Copyright 2002-2020 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.context.annotation; 018 019import java.util.Map; 020 021import javax.management.MBeanServer; 022import javax.naming.NamingException; 023 024import org.springframework.beans.factory.BeanFactory; 025import org.springframework.beans.factory.BeanFactoryAware; 026import org.springframework.beans.factory.config.BeanDefinition; 027import org.springframework.context.EnvironmentAware; 028import org.springframework.core.annotation.AnnotationAttributes; 029import org.springframework.core.env.Environment; 030import org.springframework.core.type.AnnotationMetadata; 031import org.springframework.jmx.MBeanServerNotFoundException; 032import org.springframework.jmx.export.annotation.AnnotationMBeanExporter; 033import org.springframework.jmx.support.RegistrationPolicy; 034import org.springframework.jmx.support.WebSphereMBeanServerFactoryBean; 035import org.springframework.jndi.JndiLocatorDelegate; 036import org.springframework.lang.Nullable; 037import org.springframework.util.Assert; 038import org.springframework.util.ClassUtils; 039import org.springframework.util.StringUtils; 040 041/** 042 * {@code @Configuration} class that registers a {@link AnnotationMBeanExporter} bean. 043 * 044 * <p>This configuration class is automatically imported when using the 045 * {@link EnableMBeanExport} annotation. See its javadoc for complete usage details. 046 * 047 * @author Phillip Webb 048 * @author Chris Beams 049 * @since 3.2 050 * @see EnableMBeanExport 051 */ 052@Configuration 053@Role(BeanDefinition.ROLE_INFRASTRUCTURE) 054public class MBeanExportConfiguration implements ImportAware, EnvironmentAware, BeanFactoryAware { 055 056 private static final String MBEAN_EXPORTER_BEAN_NAME = "mbeanExporter"; 057 058 @Nullable 059 private AnnotationAttributes enableMBeanExport; 060 061 @Nullable 062 private Environment environment; 063 064 @Nullable 065 private BeanFactory beanFactory; 066 067 068 @Override 069 public void setImportMetadata(AnnotationMetadata importMetadata) { 070 Map<String, Object> map = importMetadata.getAnnotationAttributes(EnableMBeanExport.class.getName()); 071 this.enableMBeanExport = AnnotationAttributes.fromMap(map); 072 if (this.enableMBeanExport == null) { 073 throw new IllegalArgumentException( 074 "@EnableMBeanExport is not present on importing class " + importMetadata.getClassName()); 075 } 076 } 077 078 @Override 079 public void setEnvironment(Environment environment) { 080 this.environment = environment; 081 } 082 083 @Override 084 public void setBeanFactory(BeanFactory beanFactory) { 085 this.beanFactory = beanFactory; 086 } 087 088 089 @Bean(name = MBEAN_EXPORTER_BEAN_NAME) 090 @Role(BeanDefinition.ROLE_INFRASTRUCTURE) 091 public AnnotationMBeanExporter mbeanExporter() { 092 AnnotationMBeanExporter exporter = new AnnotationMBeanExporter(); 093 Assert.state(this.enableMBeanExport != null, "No EnableMBeanExport annotation found"); 094 setupDomain(exporter, this.enableMBeanExport); 095 setupServer(exporter, this.enableMBeanExport); 096 setupRegistrationPolicy(exporter, this.enableMBeanExport); 097 return exporter; 098 } 099 100 private void setupDomain(AnnotationMBeanExporter exporter, AnnotationAttributes enableMBeanExport) { 101 String defaultDomain = enableMBeanExport.getString("defaultDomain"); 102 if (StringUtils.hasLength(defaultDomain) && this.environment != null) { 103 defaultDomain = this.environment.resolvePlaceholders(defaultDomain); 104 } 105 if (StringUtils.hasText(defaultDomain)) { 106 exporter.setDefaultDomain(defaultDomain); 107 } 108 } 109 110 private void setupServer(AnnotationMBeanExporter exporter, AnnotationAttributes enableMBeanExport) { 111 String server = enableMBeanExport.getString("server"); 112 if (StringUtils.hasLength(server) && this.environment != null) { 113 server = this.environment.resolvePlaceholders(server); 114 } 115 if (StringUtils.hasText(server)) { 116 Assert.state(this.beanFactory != null, "No BeanFactory set"); 117 exporter.setServer(this.beanFactory.getBean(server, MBeanServer.class)); 118 } 119 else { 120 SpecificPlatform specificPlatform = SpecificPlatform.get(); 121 if (specificPlatform != null) { 122 MBeanServer mbeanServer = specificPlatform.getMBeanServer(); 123 if (mbeanServer != null) { 124 exporter.setServer(mbeanServer); 125 } 126 } 127 } 128 } 129 130 private void setupRegistrationPolicy(AnnotationMBeanExporter exporter, AnnotationAttributes enableMBeanExport) { 131 RegistrationPolicy registrationPolicy = enableMBeanExport.getEnum("registration"); 132 exporter.setRegistrationPolicy(registrationPolicy); 133 } 134 135 136 /** 137 * Specific platforms that might need custom MBean handling. 138 */ 139 public enum SpecificPlatform { 140 141 /** 142 * Weblogic. 143 */ 144 WEBLOGIC("weblogic.management.Helper") { 145 @Override 146 public MBeanServer getMBeanServer() { 147 try { 148 return new JndiLocatorDelegate().lookup("java:comp/env/jmx/runtime", MBeanServer.class); 149 } 150 catch (NamingException ex) { 151 throw new MBeanServerNotFoundException("Failed to retrieve WebLogic MBeanServer from JNDI", ex); 152 } 153 } 154 }, 155 156 /** 157 * Websphere. 158 */ 159 WEBSPHERE("com.ibm.websphere.management.AdminServiceFactory") { 160 @Override 161 public MBeanServer getMBeanServer() { 162 WebSphereMBeanServerFactoryBean fb = new WebSphereMBeanServerFactoryBean(); 163 fb.afterPropertiesSet(); 164 return fb.getObject(); 165 } 166 }; 167 168 private final String identifyingClass; 169 170 SpecificPlatform(String identifyingClass) { 171 this.identifyingClass = identifyingClass; 172 } 173 174 @Nullable 175 public abstract MBeanServer getMBeanServer(); 176 177 @Nullable 178 public static SpecificPlatform get() { 179 ClassLoader classLoader = MBeanExportConfiguration.class.getClassLoader(); 180 for (SpecificPlatform environment : values()) { 181 if (ClassUtils.isPresent(environment.identifyingClass, classLoader)) { 182 return environment; 183 } 184 } 185 return null; 186 } 187 } 188 189}