001/*
002 * Copyright 2012-2018 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 *      http://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.boot.admin;
018
019import java.lang.management.ManagementFactory;
020
021import javax.management.MBeanServer;
022import javax.management.MalformedObjectNameException;
023import javax.management.ObjectName;
024
025import org.apache.commons.logging.Log;
026import org.apache.commons.logging.LogFactory;
027
028import org.springframework.beans.BeansException;
029import org.springframework.beans.factory.DisposableBean;
030import org.springframework.beans.factory.InitializingBean;
031import org.springframework.boot.context.event.ApplicationReadyEvent;
032import org.springframework.boot.web.context.WebServerInitializedEvent;
033import org.springframework.context.ApplicationContext;
034import org.springframework.context.ApplicationContextAware;
035import org.springframework.context.ApplicationEvent;
036import org.springframework.context.ConfigurableApplicationContext;
037import org.springframework.context.EnvironmentAware;
038import org.springframework.context.event.GenericApplicationListener;
039import org.springframework.core.Ordered;
040import org.springframework.core.ResolvableType;
041import org.springframework.core.env.Environment;
042import org.springframework.core.env.StandardEnvironment;
043import org.springframework.lang.Nullable;
044import org.springframework.util.Assert;
045
046/**
047 * Register a {@link SpringApplicationAdminMXBean} implementation to the platform
048 * {@link MBeanServer}.
049 *
050 * @author Stephane Nicoll
051 * @author Andy Wilkinson
052 * @since 1.3.0
053 */
054public class SpringApplicationAdminMXBeanRegistrar implements ApplicationContextAware,
055                GenericApplicationListener, EnvironmentAware, InitializingBean, DisposableBean {
056
057        private static final Log logger = LogFactory.getLog(SpringApplicationAdmin.class);
058
059        private ConfigurableApplicationContext applicationContext;
060
061        private Environment environment = new StandardEnvironment();
062
063        private final ObjectName objectName;
064
065        private boolean ready = false;
066
067        private boolean embeddedWebApplication = false;
068
069        public SpringApplicationAdminMXBeanRegistrar(String name)
070                        throws MalformedObjectNameException {
071                this.objectName = new ObjectName(name);
072        }
073
074        @Override
075        public void setApplicationContext(ApplicationContext applicationContext)
076                        throws BeansException {
077                Assert.state(applicationContext instanceof ConfigurableApplicationContext,
078                                "ApplicationContext does not implement ConfigurableApplicationContext");
079                this.applicationContext = (ConfigurableApplicationContext) applicationContext;
080        }
081
082        @Override
083        public void setEnvironment(Environment environment) {
084                this.environment = environment;
085        }
086
087        @Override
088        public boolean supportsEventType(ResolvableType eventType) {
089                Class<?> type = eventType.getRawClass();
090                if (type == null) {
091                        return false;
092                }
093                return ApplicationReadyEvent.class.isAssignableFrom(type)
094                                || WebServerInitializedEvent.class.isAssignableFrom(type);
095        }
096
097        @Override
098        public boolean supportsSourceType(@Nullable Class<?> sourceType) {
099                return true;
100        }
101
102        @Override
103        public void onApplicationEvent(ApplicationEvent event) {
104                if (event instanceof ApplicationReadyEvent) {
105                        onApplicationReadyEvent((ApplicationReadyEvent) event);
106                }
107                if (event instanceof WebServerInitializedEvent) {
108                        onWebServerInitializedEvent((WebServerInitializedEvent) event);
109                }
110        }
111
112        @Override
113        public int getOrder() {
114                return Ordered.HIGHEST_PRECEDENCE;
115        }
116
117        void onApplicationReadyEvent(ApplicationReadyEvent event) {
118                if (this.applicationContext.equals(event.getApplicationContext())) {
119                        this.ready = true;
120                }
121        }
122
123        void onWebServerInitializedEvent(WebServerInitializedEvent event) {
124                if (this.applicationContext.equals(event.getApplicationContext())) {
125                        this.embeddedWebApplication = true;
126                }
127        }
128
129        @Override
130        public void afterPropertiesSet() throws Exception {
131                MBeanServer server = ManagementFactory.getPlatformMBeanServer();
132                server.registerMBean(new SpringApplicationAdmin(), this.objectName);
133                if (logger.isDebugEnabled()) {
134                        logger.debug("Application Admin MBean registered with name '"
135                                        + this.objectName + "'");
136                }
137        }
138
139        @Override
140        public void destroy() throws Exception {
141                ManagementFactory.getPlatformMBeanServer().unregisterMBean(this.objectName);
142        }
143
144        private class SpringApplicationAdmin implements SpringApplicationAdminMXBean {
145
146                @Override
147                public boolean isReady() {
148                        return SpringApplicationAdminMXBeanRegistrar.this.ready;
149                }
150
151                @Override
152                public boolean isEmbeddedWebApplication() {
153                        return SpringApplicationAdminMXBeanRegistrar.this.embeddedWebApplication;
154                }
155
156                @Override
157                public String getProperty(String key) {
158                        return SpringApplicationAdminMXBeanRegistrar.this.environment
159                                        .getProperty(key);
160                }
161
162                @Override
163                public void shutdown() {
164                        logger.info("Application shutdown requested.");
165                        SpringApplicationAdminMXBeanRegistrar.this.applicationContext.close();
166                }
167
168        }
169
170}