001/*
002 * Copyright 2012-2017 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.actuate.autoconfigure;
018
019import javax.management.MBeanServer;
020
021import com.fasterxml.jackson.databind.ObjectMapper;
022
023import org.springframework.beans.factory.ObjectProvider;
024import org.springframework.boot.actuate.audit.AuditEventRepository;
025import org.springframework.boot.actuate.autoconfigure.EndpointMBeanExportAutoConfiguration.JmxEnabledCondition;
026import org.springframework.boot.actuate.condition.ConditionalOnEnabledEndpoint;
027import org.springframework.boot.actuate.endpoint.Endpoint;
028import org.springframework.boot.actuate.endpoint.jmx.AuditEventsJmxEndpoint;
029import org.springframework.boot.actuate.endpoint.jmx.EndpointMBeanExporter;
030import org.springframework.boot.autoconfigure.AutoConfigureAfter;
031import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
032import org.springframework.boot.autoconfigure.condition.ConditionMessage;
033import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
034import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
035import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
036import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
037import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;
038import org.springframework.boot.bind.RelaxedPropertyResolver;
039import org.springframework.boot.context.properties.EnableConfigurationProperties;
040import org.springframework.context.annotation.Bean;
041import org.springframework.context.annotation.ConditionContext;
042import org.springframework.context.annotation.Conditional;
043import org.springframework.context.annotation.Configuration;
044import org.springframework.core.type.AnnotatedTypeMetadata;
045import org.springframework.util.StringUtils;
046
047/**
048 * {@link EnableAutoConfiguration Auto-configuration} to enable JMX export for
049 * {@link Endpoint}s.
050 *
051 * @author Christian Dupuis
052 * @author Andy Wilkinson
053 */
054@Configuration
055@Conditional(JmxEnabledCondition.class)
056@AutoConfigureAfter({ EndpointAutoConfiguration.class, JmxAutoConfiguration.class })
057@EnableConfigurationProperties(EndpointMBeanExportProperties.class)
058public class EndpointMBeanExportAutoConfiguration {
059
060        private final EndpointMBeanExportProperties properties;
061
062        private final ObjectMapper objectMapper;
063
064        public EndpointMBeanExportAutoConfiguration(EndpointMBeanExportProperties properties,
065                        ObjectProvider<ObjectMapper> objectMapper) {
066                this.properties = properties;
067                this.objectMapper = objectMapper.getIfAvailable();
068        }
069
070        @Bean
071        public EndpointMBeanExporter endpointMBeanExporter(MBeanServer server) {
072                EndpointMBeanExporter mbeanExporter = new EndpointMBeanExporter(
073                                this.objectMapper);
074                String domain = this.properties.getDomain();
075                if (StringUtils.hasText(domain)) {
076                        mbeanExporter.setDomain(domain);
077                }
078                mbeanExporter.setServer(server);
079                mbeanExporter.setEnsureUniqueRuntimeObjectNames(this.properties.isUniqueNames());
080                mbeanExporter.setObjectNameStaticProperties(this.properties.getStaticNames());
081                return mbeanExporter;
082        }
083
084        @Bean
085        @ConditionalOnMissingBean(MBeanServer.class)
086        public MBeanServer mbeanServer() {
087                return new JmxAutoConfiguration().mbeanServer();
088        }
089
090        @Bean
091        @ConditionalOnBean(AuditEventRepository.class)
092        @ConditionalOnEnabledEndpoint("auditevents")
093        public AuditEventsJmxEndpoint auditEventsEndpoint(
094                        AuditEventRepository auditEventRepository) {
095                return new AuditEventsJmxEndpoint(this.objectMapper, auditEventRepository);
096        }
097
098        /**
099         * Condition to check that spring.jmx and endpoints.jmx are enabled.
100         */
101        static class JmxEnabledCondition extends SpringBootCondition {
102
103                @Override
104                public ConditionOutcome getMatchOutcome(ConditionContext context,
105                                AnnotatedTypeMetadata metadata) {
106                        boolean jmxEnabled = isEnabled(context, "spring.jmx.");
107                        boolean jmxEndpointsEnabled = isEnabled(context, "endpoints.jmx.");
108                        if (jmxEnabled && jmxEndpointsEnabled) {
109                                return ConditionOutcome.match(
110                                                ConditionMessage.forCondition("JMX Enabled").found("properties")
111                                                                .items("spring.jmx.enabled", "endpoints.jmx.enabled"));
112                        }
113                        return ConditionOutcome.noMatch(ConditionMessage.forCondition("JMX Enabled")
114                                        .because("spring.jmx.enabled or endpoints.jmx.enabled is not set"));
115                }
116
117                private boolean isEnabled(ConditionContext context, String prefix) {
118                        RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(
119                                        context.getEnvironment(), prefix);
120                        return resolver.getProperty("enabled", Boolean.class, true);
121                }
122
123        }
124
125}