.enabled} is {@code true}, the condition will match.
+ *
+ * This condition must be placed on a {@code @Bean} method producing an endpoint as its
+ * id and other attributes are inferred from the {@link Endpoint} annotation set on the
+ * return type of the factory method. Consider the following valid example:
+ *
+ *
+ * @Configuration
+ * public class MyAutoConfiguration {
+ *
+ * @ConditionalOnEnabledEndpoint
+ * @Bean
+ * public MyEndpoint myEndpoint() {
+ * ...
+ * }
+ *
+ * @Endpoint(id = "my", enabledByDefault = false)
+ * static class MyEndpoint { ... }
+ *
+ * }
+ *
+ *
+ * In the sample above the condition will be evaluated with the attributes specified on
+ * {@code MyEndpoint}. In particular, in the absence of any property in the environment,
+ * the condition will not match as this endpoint is disabled by default.
+ *
+ * @author Stephane Nicoll
+ * @since 2.0.0
+ * @see Endpoint
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+@Documented
+@Conditional(OnEnabledEndpointCondition.class)
+public @interface ConditionalOnEnabledEndpoint {
+
+}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/EndpointAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/EndpointAutoConfiguration.java
index ec4faf729e..940a60501b 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/EndpointAutoConfiguration.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/EndpointAutoConfiguration.java
@@ -16,8 +16,6 @@
package org.springframework.boot.actuate.autoconfigure.endpoint;
-import java.util.ArrayList;
-import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -26,11 +24,11 @@ import liquibase.integration.spring.SpringLiquibase;
import org.flywaydb.core.Flyway;
import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.boot.actuate.audit.AuditEventRepository;
+import org.springframework.boot.actuate.endpoint.AuditEventsEndpoint;
import org.springframework.boot.actuate.endpoint.AutoConfigurationReportEndpoint;
import org.springframework.boot.actuate.endpoint.BeansEndpoint;
import org.springframework.boot.actuate.endpoint.ConfigurationPropertiesReportEndpoint;
-import org.springframework.boot.actuate.endpoint.DumpEndpoint;
-import org.springframework.boot.actuate.endpoint.Endpoint;
import org.springframework.boot.actuate.endpoint.EndpointProperties;
import org.springframework.boot.actuate.endpoint.EnvironmentEndpoint;
import org.springframework.boot.actuate.endpoint.FlywayEndpoint;
@@ -42,6 +40,7 @@ import org.springframework.boot.actuate.endpoint.MetricsEndpoint;
import org.springframework.boot.actuate.endpoint.PublicMetrics;
import org.springframework.boot.actuate.endpoint.RequestMappingEndpoint;
import org.springframework.boot.actuate.endpoint.ShutdownEndpoint;
+import org.springframework.boot.actuate.endpoint.ThreadDumpEndpoint;
import org.springframework.boot.actuate.endpoint.TraceEndpoint;
import org.springframework.boot.actuate.health.HealthAggregator;
import org.springframework.boot.actuate.health.HealthIndicator;
@@ -59,10 +58,12 @@ import org.springframework.boot.autoconfigure.condition.SearchStrategy;
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.boot.endpoint.Endpoint;
import org.springframework.boot.logging.LoggingSystem;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
+import org.springframework.core.env.Environment;
import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;
/**
@@ -78,114 +79,112 @@ import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;
* @author Meang Akira Tanaka
* @author Ben Hale
* @since 2.0.0
+ * @author Andy Wilkinson
*/
@Configuration
@AutoConfigureAfter({ FlywayAutoConfiguration.class, LiquibaseAutoConfiguration.class })
@EnableConfigurationProperties(EndpointProperties.class)
public class EndpointAutoConfiguration {
- private final HealthAggregator healthAggregator;
-
- private final Map healthIndicators;
-
- private final List infoContributors;
-
- private final Collection publicMetrics;
-
- private final TraceRepository traceRepository;
-
- public EndpointAutoConfiguration(ObjectProvider healthAggregator,
- ObjectProvider> healthIndicators,
- ObjectProvider> infoContributors,
- ObjectProvider> publicMetrics,
- ObjectProvider traceRepository) {
- this.healthAggregator = healthAggregator.getIfAvailable();
- this.healthIndicators = healthIndicators.getIfAvailable();
- this.infoContributors = infoContributors.getIfAvailable();
- this.publicMetrics = publicMetrics.getIfAvailable();
- this.traceRepository = traceRepository.getIfAvailable();
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnEnabledEndpoint
+ public EnvironmentEndpoint environmentEndpoint(Environment environment) {
+ return new EnvironmentEndpoint(environment);
}
@Bean
@ConditionalOnMissingBean
- public EnvironmentEndpoint environmentEndpoint() {
- return new EnvironmentEndpoint();
- }
-
- @Bean
- @ConditionalOnMissingBean
- public HealthEndpoint healthEndpoint() {
+ @ConditionalOnEnabledEndpoint
+ public HealthEndpoint healthEndpoint(
+ ObjectProvider healthAggregator,
+ ObjectProvider> healthIndicators) {
return new HealthEndpoint(
- this.healthAggregator == null ? new OrderedHealthAggregator()
- : this.healthAggregator,
- this.healthIndicators == null
- ? Collections.emptyMap()
- : this.healthIndicators);
+ healthAggregator.getIfAvailable(() -> new OrderedHealthAggregator()),
+ healthIndicators.getIfAvailable(Collections::emptyMap));
}
@Bean
@ConditionalOnMissingBean
+ @ConditionalOnEnabledEndpoint
public BeansEndpoint beansEndpoint() {
return new BeansEndpoint();
}
@Bean
@ConditionalOnMissingBean
- public InfoEndpoint infoEndpoint() throws Exception {
- return new InfoEndpoint(this.infoContributors == null
- ? Collections.emptyList() : this.infoContributors);
+ @ConditionalOnEnabledEndpoint
+ public InfoEndpoint infoEndpoint(
+ ObjectProvider> infoContributors) {
+ return new InfoEndpoint(infoContributors.getIfAvailable(Collections::emptyList));
}
@Bean
@ConditionalOnBean(LoggingSystem.class)
@ConditionalOnMissingBean
+ @ConditionalOnEnabledEndpoint
public LoggersEndpoint loggersEndpoint(LoggingSystem loggingSystem) {
return new LoggersEndpoint(loggingSystem);
}
@Bean
@ConditionalOnMissingBean
- public MetricsEndpoint metricsEndpoint() {
- List publicMetrics = new ArrayList<>();
- if (this.publicMetrics != null) {
- publicMetrics.addAll(this.publicMetrics);
- }
- publicMetrics.sort(AnnotationAwareOrderComparator.INSTANCE);
- return new MetricsEndpoint(publicMetrics);
+ @ConditionalOnEnabledEndpoint
+ public MetricsEndpoint metricsEndpoint(
+ ObjectProvider> publicMetrics) {
+ List sortedPublicMetrics = publicMetrics
+ .getIfAvailable(Collections::emptyList);
+ Collections.sort(sortedPublicMetrics, AnnotationAwareOrderComparator.INSTANCE);
+ return new MetricsEndpoint(sortedPublicMetrics);
}
@Bean
@ConditionalOnMissingBean
- public TraceEndpoint traceEndpoint() {
- return new TraceEndpoint(this.traceRepository == null
- ? new InMemoryTraceRepository() : this.traceRepository);
+ @ConditionalOnEnabledEndpoint
+ public TraceEndpoint traceEndpoint(ObjectProvider traceRepository) {
+ return new TraceEndpoint(
+ traceRepository.getIfAvailable(() -> new InMemoryTraceRepository()));
}
@Bean
@ConditionalOnMissingBean
- public DumpEndpoint dumpEndpoint() {
- return new DumpEndpoint();
+ @ConditionalOnEnabledEndpoint
+ public ThreadDumpEndpoint dumpEndpoint() {
+ return new ThreadDumpEndpoint();
}
@Bean
@ConditionalOnBean(ConditionEvaluationReport.class)
@ConditionalOnMissingBean(search = SearchStrategy.CURRENT)
- public AutoConfigurationReportEndpoint autoConfigurationReportEndpoint() {
- return new AutoConfigurationReportEndpoint();
+ @ConditionalOnEnabledEndpoint
+ public AutoConfigurationReportEndpoint autoConfigurationReportEndpoint(
+ ConditionEvaluationReport conditionEvaluationReport) {
+ return new AutoConfigurationReportEndpoint(conditionEvaluationReport);
}
@Bean
@ConditionalOnMissingBean
+ @ConditionalOnEnabledEndpoint
public ShutdownEndpoint shutdownEndpoint() {
return new ShutdownEndpoint();
}
@Bean
@ConditionalOnMissingBean
+ @ConditionalOnEnabledEndpoint
public ConfigurationPropertiesReportEndpoint configurationPropertiesReportEndpoint() {
return new ConfigurationPropertiesReportEndpoint();
}
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnBean(AuditEventRepository.class)
+ @ConditionalOnEnabledEndpoint
+ public AuditEventsEndpoint auditEventsEndpoint(
+ AuditEventRepository auditEventRepository) {
+ return new AuditEventsEndpoint(auditEventRepository);
+ }
+
@Configuration
@ConditionalOnBean(Flyway.class)
@ConditionalOnClass(Flyway.class)
@@ -193,6 +192,7 @@ public class EndpointAutoConfiguration {
@Bean
@ConditionalOnMissingBean
+ @ConditionalOnEnabledEndpoint
public FlywayEndpoint flywayEndpoint(Map flyways) {
return new FlywayEndpoint(flyways);
}
@@ -206,6 +206,7 @@ public class EndpointAutoConfiguration {
@Bean
@ConditionalOnMissingBean
+ @ConditionalOnEnabledEndpoint
public LiquibaseEndpoint liquibaseEndpoint(
Map liquibases) {
return new LiquibaseEndpoint(liquibases);
@@ -219,6 +220,7 @@ public class EndpointAutoConfiguration {
@Bean
@ConditionalOnMissingBean
+ @ConditionalOnEnabledEndpoint
public RequestMappingEndpoint requestMappingEndpoint() {
RequestMappingEndpoint endpoint = new RequestMappingEndpoint();
return endpoint;
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/EndpointMBeanExportAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/EndpointMBeanExportAutoConfiguration.java
deleted file mode 100644
index 811004e5a8..0000000000
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/EndpointMBeanExportAutoConfiguration.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright 2012-2017 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.boot.actuate.autoconfigure.endpoint;
-
-import javax.management.MBeanServer;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-import org.springframework.beans.factory.ObjectProvider;
-import org.springframework.boot.actuate.audit.AuditEventRepository;
-import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointMBeanExportAutoConfiguration.JmxEnabledCondition;
-import org.springframework.boot.actuate.condition.ConditionalOnEnabledEndpoint;
-import org.springframework.boot.actuate.endpoint.Endpoint;
-import org.springframework.boot.actuate.endpoint.jmx.AuditEventsJmxEndpoint;
-import org.springframework.boot.actuate.endpoint.jmx.EndpointMBeanExporter;
-import org.springframework.boot.autoconfigure.AutoConfigureAfter;
-import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
-import org.springframework.boot.autoconfigure.condition.ConditionMessage;
-import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
-import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
-import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;
-import org.springframework.boot.context.properties.EnableConfigurationProperties;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.ConditionContext;
-import org.springframework.context.annotation.Conditional;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.core.type.AnnotatedTypeMetadata;
-import org.springframework.util.StringUtils;
-
-/**
- * {@link EnableAutoConfiguration Auto-configuration} to enable JMX export for
- * {@link Endpoint}s.
- *
- * @author Christian Dupuis
- * @author Andy Wilkinson
- * @author Madhura Bhave
- * @since 2.0.0
- */
-@Configuration
-@Conditional(JmxEnabledCondition.class)
-@AutoConfigureAfter({ EndpointAutoConfiguration.class, JmxAutoConfiguration.class })
-@EnableConfigurationProperties(EndpointMBeanExportProperties.class)
-public class EndpointMBeanExportAutoConfiguration {
-
- private final EndpointMBeanExportProperties properties;
-
- private final ObjectMapper objectMapper;
-
- public EndpointMBeanExportAutoConfiguration(EndpointMBeanExportProperties properties,
- ObjectProvider objectMapper) {
- this.properties = properties;
- this.objectMapper = objectMapper.getIfAvailable();
- }
-
- @Bean
- public EndpointMBeanExporter endpointMBeanExporter(MBeanServer server) {
- EndpointMBeanExporter mbeanExporter = new EndpointMBeanExporter(
- this.objectMapper);
- String domain = this.properties.getDomain();
- if (StringUtils.hasText(domain)) {
- mbeanExporter.setDomain(domain);
- }
- mbeanExporter.setServer(server);
- mbeanExporter.setEnsureUniqueRuntimeObjectNames(this.properties.isUniqueNames());
- mbeanExporter.setObjectNameStaticProperties(this.properties.getStaticNames());
- return mbeanExporter;
- }
-
- @Bean
- @ConditionalOnMissingBean(MBeanServer.class)
- public MBeanServer mbeanServer() {
- return new JmxAutoConfiguration().mbeanServer();
- }
-
- @Bean
- @ConditionalOnBean(AuditEventRepository.class)
- @ConditionalOnEnabledEndpoint("auditevents")
- public AuditEventsJmxEndpoint auditEventsEndpoint(
- AuditEventRepository auditEventRepository) {
- return new AuditEventsJmxEndpoint(this.objectMapper, auditEventRepository);
- }
-
- /**
- * Condition to check that spring.jmx and endpoints.jmx are enabled.
- */
- static class JmxEnabledCondition extends SpringBootCondition {
-
- @Override
- public ConditionOutcome getMatchOutcome(ConditionContext context,
- AnnotatedTypeMetadata metadata) {
- boolean jmxEnabled = context.getEnvironment()
- .getProperty("spring.jmx.enabled", Boolean.class, true);
- boolean jmxEndpointsEnabled = context.getEnvironment()
- .getProperty("endpoints.jmx.enabled", Boolean.class, true);
- if (jmxEnabled && jmxEndpointsEnabled) {
- return ConditionOutcome.match(
- ConditionMessage.forCondition("JMX Enabled").found("properties")
- .items("spring.jmx.enabled", "endpoints.jmx.enabled"));
- }
- return ConditionOutcome.noMatch(ConditionMessage.forCondition("JMX Enabled")
- .because("spring.jmx.enabled or endpoints.jmx.enabled is not set"));
- }
-
- }
-
-}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/EndpointMBeanExportProperties.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/EndpointMBeanExportProperties.java
deleted file mode 100644
index b415742fb6..0000000000
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/EndpointMBeanExportProperties.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright 2012-2017 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.boot.actuate.autoconfigure.endpoint;
-
-import java.util.Properties;
-
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.util.StringUtils;
-
-/**
- * Configuration properties for JMX endpoints.
- *
- * @author Christian Dupuis
- * @since 2.0.0
- */
-@ConfigurationProperties(prefix = "endpoints.jmx")
-public class EndpointMBeanExportProperties {
-
- /**
- * JMX domain name. Initialized with the value of 'spring.jmx.default-domain' if set.
- */
- @Value("${spring.jmx.default-domain:}")
- private String domain;
-
- /**
- * Ensure that ObjectNames are modified in case of conflict.
- */
- private boolean uniqueNames = false;
-
- /**
- * Enable the JMX endpoints.
- */
- private boolean enabled = true;
-
- /**
- * Additional static properties to append to all ObjectNames of MBeans representing
- * Endpoints.
- */
- private Properties staticNames = new Properties();
-
- public boolean isEnabled() {
- return this.enabled;
- }
-
- public void setEnabled(boolean enabled) {
- this.enabled = enabled;
- }
-
- public String getDomain() {
- return this.domain;
- }
-
- public void setDomain(String domain) {
- this.domain = domain;
- }
-
- public boolean isUniqueNames() {
- return this.uniqueNames;
- }
-
- public void setUniqueNames(boolean uniqueNames) {
- this.uniqueNames = uniqueNames;
- }
-
- public Properties getStaticNames() {
- return this.staticNames;
- }
-
- public void setStaticNames(String[] staticNames) {
- this.staticNames = StringUtils.splitArrayElementsIntoProperties(staticNames, "=");
- }
-
-}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/EndpointWebMvcAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/EndpointWebMvcAutoConfiguration.java
deleted file mode 100644
index e4194080e6..0000000000
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/EndpointWebMvcAutoConfiguration.java
+++ /dev/null
@@ -1,363 +0,0 @@
-/*
- * Copyright 2012-2017 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.boot.actuate.autoconfigure.endpoint;
-
-import java.lang.reflect.Modifier;
-
-import javax.servlet.Servlet;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import org.springframework.beans.BeansException;
-import org.springframework.beans.FatalBeanException;
-import org.springframework.beans.factory.NoSuchBeanDefinitionException;
-import org.springframework.beans.factory.SmartInitializingSingleton;
-import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
-import org.springframework.beans.factory.support.BeanDefinitionRegistry;
-import org.springframework.beans.factory.support.RootBeanDefinition;
-import org.springframework.boot.actuate.autoconfigure.web.ManagementServerProperties;
-import org.springframework.boot.actuate.endpoint.Endpoint;
-import org.springframework.boot.actuate.endpoint.mvc.ManagementServletContext;
-import org.springframework.boot.autoconfigure.AutoConfigureAfter;
-import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
-import org.springframework.boot.autoconfigure.condition.ConditionMessage;
-import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
-import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
-import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
-import org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration;
-import org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration;
-import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
-import org.springframework.boot.autoconfigure.web.ServerProperties;
-import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
-import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
-import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
-import org.springframework.boot.context.event.ApplicationFailedEvent;
-import org.springframework.boot.context.properties.EnableConfigurationProperties;
-import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
-import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext;
-import org.springframework.boot.web.servlet.filter.ApplicationContextHeaderFilter;
-import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
-import org.springframework.context.ApplicationEvent;
-import org.springframework.context.ApplicationListener;
-import org.springframework.context.ConfigurableApplicationContext;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.ConditionContext;
-import org.springframework.context.annotation.Conditional;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.ConfigurationCondition;
-import org.springframework.context.annotation.Import;
-import org.springframework.context.event.ContextClosedEvent;
-import org.springframework.core.env.ConfigurableEnvironment;
-import org.springframework.core.env.Environment;
-import org.springframework.core.env.PropertySource;
-import org.springframework.core.type.AnnotatedTypeMetadata;
-import org.springframework.web.context.WebApplicationContext;
-import org.springframework.web.servlet.DispatcherServlet;
-
-/**
- * {@link EnableAutoConfiguration Auto-configuration} to enable Spring MVC to handle
- * {@link Endpoint} requests. If the {@link ManagementServerProperties} specifies a
- * different port to {@link ServerProperties} a new child context is created, otherwise it
- * is assumed that endpoint requests will be mapped and handled via an already registered
- * {@link DispatcherServlet}.
- *
- * @author Dave Syer
- * @author Phillip Webb
- * @author Christian Dupuis
- * @author Andy Wilkinson
- * @author Johannes Edmeier
- * @author EddĂș MelĂ©ndez
- * @author Venil Noronha
- * @author Madhura Bhave
- * @since 2.0.0
- */
-@Configuration
-@ConditionalOnClass({ Servlet.class, DispatcherServlet.class })
-@ConditionalOnWebApplication(type = Type.SERVLET)
-@EnableConfigurationProperties(ManagementServerProperties.class)
-@AutoConfigureAfter({ EndpointAutoConfiguration.class,
- PropertyPlaceholderAutoConfiguration.class,
- ServletWebServerFactoryAutoConfiguration.class, WebMvcAutoConfiguration.class,
- RepositoryRestMvcAutoConfiguration.class, HypermediaAutoConfiguration.class,
- HttpMessageConvertersAutoConfiguration.class })
-public class EndpointWebMvcAutoConfiguration
- implements ApplicationContextAware, SmartInitializingSingleton {
-
- private static final Log logger = LogFactory
- .getLog(EndpointWebMvcAutoConfiguration.class);
-
- private ApplicationContext applicationContext;
-
- @Override
- public void setApplicationContext(ApplicationContext applicationContext)
- throws BeansException {
- this.applicationContext = applicationContext;
- }
-
- @Bean
- public ManagementContextResolver managementContextResolver() {
- return new ManagementContextResolver(this.applicationContext);
- }
-
- @Bean
- public ManagementServletContext managementServletContext(
- final ManagementServerProperties properties) {
- return properties::getContextPath;
- }
-
- @Override
- public void afterSingletonsInstantiated() {
- ManagementServerPort managementPort = ManagementServerPort.DIFFERENT;
- Environment environment = this.applicationContext.getEnvironment();
- if (this.applicationContext instanceof WebApplicationContext) {
- managementPort = ManagementServerPort.get(environment);
- }
- if (managementPort == ManagementServerPort.DIFFERENT) {
- if (this.applicationContext instanceof ServletWebServerApplicationContext
- && ((ServletWebServerApplicationContext) this.applicationContext)
- .getWebServer() != null) {
- createChildManagementContext();
- }
- else {
- logger.warn("Could not start management web server on "
- + "different port (management endpoints are still available "
- + "through JMX)");
- }
- }
- if (managementPort == ManagementServerPort.SAME) {
- String contextPath = environment.getProperty("management.context-path");
- if ("".equals(contextPath) || "/".equals(contextPath)) {
- throw new IllegalStateException("A management context path of '"
- + contextPath + "' requires the management server to be "
- + "listening on a separate port");
- }
- if (environment.getProperty("management.ssl.enabled", Boolean.class, false)) {
- throw new IllegalStateException(
- "Management-specific SSL cannot be configured as the management "
- + "server is not listening on a separate port");
- }
- if (environment instanceof ConfigurableEnvironment) {
- addLocalManagementPortPropertyAlias(
- (ConfigurableEnvironment) environment);
- }
- }
- }
-
- private void createChildManagementContext() {
- AnnotationConfigServletWebServerApplicationContext childContext = new AnnotationConfigServletWebServerApplicationContext();
- childContext.setParent(this.applicationContext);
- childContext.setNamespace("management");
- childContext.setId(this.applicationContext.getId() + ":management");
- childContext.setClassLoader(this.applicationContext.getClassLoader());
- childContext.register(EndpointWebMvcChildContextConfiguration.class,
- PropertyPlaceholderAutoConfiguration.class,
- ServletWebServerFactoryAutoConfiguration.class,
- DispatcherServletAutoConfiguration.class);
- registerServletWebServerFactory(childContext);
- CloseManagementContextListener.addIfPossible(this.applicationContext,
- childContext);
- childContext.refresh();
- managementContextResolver().setApplicationContext(childContext);
- }
-
- private void registerServletWebServerFactory(
- AnnotationConfigServletWebServerApplicationContext childContext) {
- try {
- ConfigurableListableBeanFactory beanFactory = childContext.getBeanFactory();
- if (beanFactory instanceof BeanDefinitionRegistry) {
- BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
- registry.registerBeanDefinition("ServletWebServerFactory",
- new RootBeanDefinition(determineServletWebServerFactoryClass()));
- }
- }
- catch (NoSuchBeanDefinitionException ex) {
- // Ignore and assume auto-configuration
- }
- }
-
- private Class> determineServletWebServerFactoryClass()
- throws NoSuchBeanDefinitionException {
- Class> factoryClass = this.applicationContext
- .getBean(ServletWebServerFactory.class).getClass();
- if (cannotBeInstantiated(factoryClass)) {
- throw new FatalBeanException("ServletWebServerFactory implementation "
- + factoryClass.getName() + " cannot be instantiated. "
- + "To allow a separate management port to be used, a top-level class "
- + "or static inner class should be used instead");
- }
- return factoryClass;
- }
-
- private boolean cannotBeInstantiated(Class> clazz) {
- return clazz.isLocalClass()
- || (clazz.isMemberClass() && !Modifier.isStatic(clazz.getModifiers()))
- || clazz.isAnonymousClass();
- }
-
- /**
- * Add an alias for 'local.management.port' that actually resolves using
- * 'local.server.port'.
- * @param environment the environment
- */
- private void addLocalManagementPortPropertyAlias(
- final ConfigurableEnvironment environment) {
- environment.getPropertySources()
- .addLast(new PropertySource("Management Server") {
- @Override
- public Object getProperty(String name) {
- if ("local.management.port".equals(name)) {
- return environment.getProperty("local.server.port");
- }
- return null;
- }
- });
- }
-
- // Put Servlets and Filters in their own nested class so they don't force early
- // instantiation of ManagementServerProperties.
- @Configuration
- @ConditionalOnProperty(prefix = "management", name = "add-application-context-header", havingValue = "true")
- protected static class ApplicationContextFilterConfiguration {
-
- @Bean
- public ApplicationContextHeaderFilter applicationContextIdFilter(
- ApplicationContext context) {
- return new ApplicationContextHeaderFilter(context);
- }
-
- }
-
- @Configuration
- @Conditional(OnManagementMvcCondition.class)
- @Import(ManagementContextConfigurationsImportSelector.class)
- protected static class EndpointWebMvcConfiguration {
-
- }
-
- /**
- * {@link ApplicationListener} to propagate the {@link ContextClosedEvent} and
- * {@link ApplicationFailedEvent} from a parent to a child.
- */
- private static class CloseManagementContextListener
- implements ApplicationListener {
-
- private final ApplicationContext parentContext;
-
- private final ConfigurableApplicationContext childContext;
-
- CloseManagementContextListener(ApplicationContext parentContext,
- ConfigurableApplicationContext childContext) {
- this.parentContext = parentContext;
- this.childContext = childContext;
- }
-
- @Override
- public void onApplicationEvent(ApplicationEvent event) {
- if (event instanceof ContextClosedEvent) {
- onContextClosedEvent((ContextClosedEvent) event);
- }
- if (event instanceof ApplicationFailedEvent) {
- onApplicationFailedEvent((ApplicationFailedEvent) event);
- }
- };
-
- private void onContextClosedEvent(ContextClosedEvent event) {
- propagateCloseIfNecessary(event.getApplicationContext());
- }
-
- private void onApplicationFailedEvent(ApplicationFailedEvent event) {
- propagateCloseIfNecessary(event.getApplicationContext());
- }
-
- private void propagateCloseIfNecessary(ApplicationContext applicationContext) {
- if (applicationContext == this.parentContext) {
- this.childContext.close();
- }
- }
-
- public static void addIfPossible(ApplicationContext parentContext,
- ConfigurableApplicationContext childContext) {
- if (parentContext instanceof ConfigurableApplicationContext) {
- add((ConfigurableApplicationContext) parentContext, childContext);
- }
- }
-
- private static void add(ConfigurableApplicationContext parentContext,
- ConfigurableApplicationContext childContext) {
- parentContext.addApplicationListener(
- new CloseManagementContextListener(parentContext, childContext));
- }
-
- }
-
- private static class OnManagementMvcCondition extends SpringBootCondition
- implements ConfigurationCondition {
-
- @Override
- public ConfigurationPhase getConfigurationPhase() {
- return ConfigurationPhase.REGISTER_BEAN;
- }
-
- @Override
- public ConditionOutcome getMatchOutcome(ConditionContext context,
- AnnotatedTypeMetadata metadata) {
- ConditionMessage.Builder message = ConditionMessage
- .forCondition("Management Server MVC");
- if (!(context.getResourceLoader() instanceof WebApplicationContext)) {
- return ConditionOutcome
- .noMatch(message.because("non WebApplicationContext"));
- }
- ManagementServerPort port = ManagementServerPort
- .get(context.getEnvironment());
- if (port == ManagementServerPort.SAME) {
- return ConditionOutcome.match(message.because("port is same"));
- }
- return ConditionOutcome.noMatch(message.because("port is not same"));
- }
-
- }
-
- protected enum ManagementServerPort {
-
- DISABLE, SAME, DIFFERENT;
-
- public static ManagementServerPort get(Environment environment) {
- Integer serverPort = getPortProperty(environment, "server.");
- Integer managementPort = getPortProperty(environment, "management.");
- if (managementPort != null && managementPort < 0) {
- return DISABLE;
- }
- return ((managementPort == null)
- || (serverPort == null && managementPort.equals(8080))
- || (managementPort != 0 && managementPort.equals(serverPort)) ? SAME
- : DIFFERENT);
- }
-
- private static Integer getPortProperty(Environment environment, String prefix) {
- return environment.getProperty(prefix + "port", Integer.class);
- }
-
- }
-
-}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/EndpointWebMvcManagementContextConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/EndpointWebMvcManagementContextConfiguration.java
deleted file mode 100644
index d68fb4f8c3..0000000000
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/EndpointWebMvcManagementContextConfiguration.java
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * Copyright 2012-2017 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.boot.actuate.autoconfigure.endpoint;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-
-import org.springframework.beans.factory.ObjectProvider;
-import org.springframework.boot.actuate.audit.AuditEventRepository;
-import org.springframework.boot.actuate.autoconfigure.ManagementContextConfiguration;
-import org.springframework.boot.actuate.autoconfigure.health.HealthMvcEndpointProperties;
-import org.springframework.boot.actuate.autoconfigure.web.ManagementServerProperties;
-import org.springframework.boot.actuate.condition.ConditionalOnEnabledEndpoint;
-import org.springframework.boot.actuate.endpoint.Endpoint;
-import org.springframework.boot.actuate.endpoint.EnvironmentEndpoint;
-import org.springframework.boot.actuate.endpoint.HealthEndpoint;
-import org.springframework.boot.actuate.endpoint.LoggersEndpoint;
-import org.springframework.boot.actuate.endpoint.MetricsEndpoint;
-import org.springframework.boot.actuate.endpoint.ShutdownEndpoint;
-import org.springframework.boot.actuate.endpoint.mvc.AuditEventsMvcEndpoint;
-import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping;
-import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMappingCustomizer;
-import org.springframework.boot.actuate.endpoint.mvc.EnvironmentMvcEndpoint;
-import org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint;
-import org.springframework.boot.actuate.endpoint.mvc.HeapdumpMvcEndpoint;
-import org.springframework.boot.actuate.endpoint.mvc.LogFileMvcEndpoint;
-import org.springframework.boot.actuate.endpoint.mvc.LoggersMvcEndpoint;
-import org.springframework.boot.actuate.endpoint.mvc.MetricsMvcEndpoint;
-import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
-import org.springframework.boot.actuate.endpoint.mvc.MvcEndpointSecurityInterceptor;
-import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoints;
-import org.springframework.boot.actuate.endpoint.mvc.ShutdownMvcEndpoint;
-import org.springframework.boot.autoconfigure.condition.ConditionMessage;
-import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
-import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
-import org.springframework.boot.context.properties.EnableConfigurationProperties;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.ConditionContext;
-import org.springframework.context.annotation.Conditional;
-import org.springframework.core.env.Environment;
-import org.springframework.core.type.AnnotatedTypeMetadata;
-import org.springframework.util.CollectionUtils;
-import org.springframework.util.StringUtils;
-import org.springframework.web.cors.CorsConfiguration;
-
-/**
- * Configuration to expose {@link Endpoint} instances over Spring MVC.
- *
- * @author Dave Syer
- * @author Ben Hale
- * @author Vedran Pavic
- * @author Madhura Bhave
- * @since 2.0.0
- */
-@ManagementContextConfiguration
-@EnableConfigurationProperties({ HealthMvcEndpointProperties.class,
- EndpointCorsProperties.class })
-public class EndpointWebMvcManagementContextConfiguration {
-
- private final HealthMvcEndpointProperties healthMvcEndpointProperties;
-
- private final ManagementServerProperties managementServerProperties;
-
- private final EndpointCorsProperties corsProperties;
-
- private final List mappingCustomizers;
-
- public EndpointWebMvcManagementContextConfiguration(
- HealthMvcEndpointProperties healthMvcEndpointProperties,
- ManagementServerProperties managementServerProperties,
- EndpointCorsProperties corsProperties,
- ObjectProvider> mappingCustomizers) {
- this.healthMvcEndpointProperties = healthMvcEndpointProperties;
- this.managementServerProperties = managementServerProperties;
- this.corsProperties = corsProperties;
- List providedCustomizers = mappingCustomizers
- .getIfAvailable();
- this.mappingCustomizers = providedCustomizers == null
- ? Collections.emptyList()
- : providedCustomizers;
- }
-
- @Bean
- @ConditionalOnMissingBean
- public EndpointHandlerMapping endpointHandlerMapping() {
- Set endpoints = mvcEndpoints().getEndpoints();
- CorsConfiguration corsConfiguration = getCorsConfiguration(this.corsProperties);
- EndpointHandlerMapping mapping = new EndpointHandlerMapping(endpoints,
- corsConfiguration);
- mapping.setPrefix(this.managementServerProperties.getContextPath());
- MvcEndpointSecurityInterceptor securityInterceptor = new MvcEndpointSecurityInterceptor(
- this.managementServerProperties.getSecurity().isEnabled(),
- this.managementServerProperties.getSecurity().getRoles());
- mapping.setSecurityInterceptor(securityInterceptor);
- for (EndpointHandlerMappingCustomizer customizer : this.mappingCustomizers) {
- customizer.customize(mapping);
- }
- return mapping;
- }
-
- private CorsConfiguration getCorsConfiguration(EndpointCorsProperties properties) {
- if (CollectionUtils.isEmpty(properties.getAllowedOrigins())) {
- return null;
- }
- CorsConfiguration configuration = new CorsConfiguration();
- configuration.setAllowedOrigins(properties.getAllowedOrigins());
- if (!CollectionUtils.isEmpty(properties.getAllowedHeaders())) {
- configuration.setAllowedHeaders(properties.getAllowedHeaders());
- }
- if (!CollectionUtils.isEmpty(properties.getAllowedMethods())) {
- configuration.setAllowedMethods(properties.getAllowedMethods());
- }
- if (!CollectionUtils.isEmpty(properties.getExposedHeaders())) {
- configuration.setExposedHeaders(properties.getExposedHeaders());
- }
- if (properties.getMaxAge() != null) {
- configuration.setMaxAge(properties.getMaxAge());
- }
- if (properties.getAllowCredentials() != null) {
- configuration.setAllowCredentials(properties.getAllowCredentials());
- }
- return configuration;
- }
-
- @Bean
- @ConditionalOnMissingBean
- public MvcEndpoints mvcEndpoints() {
- return new MvcEndpoints();
- }
-
- @Bean
- @ConditionalOnBean(EnvironmentEndpoint.class)
- @ConditionalOnEnabledEndpoint("env")
- public EnvironmentMvcEndpoint environmentMvcEndpoint(EnvironmentEndpoint delegate) {
- return new EnvironmentMvcEndpoint(delegate);
- }
-
- @Bean
- @ConditionalOnMissingBean
- @ConditionalOnEnabledEndpoint("heapdump")
- public HeapdumpMvcEndpoint heapdumpMvcEndpoint() {
- return new HeapdumpMvcEndpoint();
- }
-
- @Bean
- @ConditionalOnBean(HealthEndpoint.class)
- @ConditionalOnMissingBean
- @ConditionalOnEnabledEndpoint("health")
- public HealthMvcEndpoint healthMvcEndpoint(HealthEndpoint delegate,
- ManagementServerProperties managementServerProperties) {
- HealthMvcEndpoint healthMvcEndpoint = new HealthMvcEndpoint(delegate,
- this.managementServerProperties.getSecurity().isEnabled(),
- managementServerProperties.getSecurity().getRoles());
- if (this.healthMvcEndpointProperties.getMapping() != null) {
- healthMvcEndpoint
- .addStatusMapping(this.healthMvcEndpointProperties.getMapping());
- }
- return healthMvcEndpoint;
- }
-
- @Bean
- @ConditionalOnBean(LoggersEndpoint.class)
- @ConditionalOnEnabledEndpoint("loggers")
- public LoggersMvcEndpoint loggersMvcEndpoint(LoggersEndpoint delegate) {
- return new LoggersMvcEndpoint(delegate);
- }
-
- @Bean
- @ConditionalOnBean(MetricsEndpoint.class)
- @ConditionalOnEnabledEndpoint("metrics")
- public MetricsMvcEndpoint metricsMvcEndpoint(MetricsEndpoint delegate) {
- return new MetricsMvcEndpoint(delegate);
- }
-
- @Bean
- @ConditionalOnEnabledEndpoint("logfile")
- @Conditional(LogFileCondition.class)
- public LogFileMvcEndpoint logfileMvcEndpoint() {
- return new LogFileMvcEndpoint();
- }
-
- @Bean
- @ConditionalOnBean(ShutdownEndpoint.class)
- @ConditionalOnEnabledEndpoint(value = "shutdown", enabledByDefault = false)
- public ShutdownMvcEndpoint shutdownMvcEndpoint(ShutdownEndpoint delegate) {
- return new ShutdownMvcEndpoint(delegate);
- }
-
- @Bean
- @ConditionalOnBean(AuditEventRepository.class)
- @ConditionalOnEnabledEndpoint("auditevents")
- public AuditEventsMvcEndpoint auditEventMvcEndpoint(
- AuditEventRepository auditEventRepository) {
- return new AuditEventsMvcEndpoint(auditEventRepository);
- }
-
- private static class LogFileCondition extends SpringBootCondition {
-
- @Override
- public ConditionOutcome getMatchOutcome(ConditionContext context,
- AnnotatedTypeMetadata metadata) {
- Environment environment = context.getEnvironment();
- String config = environment.resolvePlaceholders("${logging.file:}");
- ConditionMessage.Builder message = ConditionMessage.forCondition("Log File");
- if (StringUtils.hasText(config)) {
- return ConditionOutcome
- .match(message.found("logging.file").items(config));
- }
- config = environment.resolvePlaceholders("${logging.path:}");
- if (StringUtils.hasText(config)) {
- return ConditionOutcome
- .match(message.found("logging.path").items(config));
- }
- config = environment.getProperty("endpoints.logfile.external-file");
- if (StringUtils.hasText(config)) {
- return ConditionOutcome.match(
- message.found("endpoints.logfile.external-file").items(config));
- }
- return ConditionOutcome.noMatch(message.didNotFind("logging file").atAll());
- }
-
- }
-
-}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/ManagementContextResolver.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/ManagementContextResolver.java
index 1be0288559..9318eb69b0 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/ManagementContextResolver.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/ManagementContextResolver.java
@@ -16,7 +16,6 @@
package org.springframework.boot.actuate.autoconfigure.endpoint;
-import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoints;
import org.springframework.context.ApplicationContext;
/**
@@ -34,23 +33,6 @@ public class ManagementContextResolver {
this.applicationContext = applicationContext;
}
- void setApplicationContext(ApplicationContext applicationContext) {
- this.applicationContext = applicationContext;
- }
-
- /**
- * Return all {@link MvcEndpoints} from the management context.
- * @return {@link MvcEndpoints} from the management context
- */
- public MvcEndpoints getMvcEndpoints() {
- try {
- return getApplicationContext().getBean(MvcEndpoints.class);
- }
- catch (Exception ex) {
- return null;
- }
- }
-
/**
* Return the management {@link ApplicationContext}.
* @return the management {@link ApplicationContext}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/OnEnabledEndpointCondition.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/OnEnabledEndpointCondition.java
new file mode 100644
index 0000000000..f99ad69b02
--- /dev/null
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/OnEnabledEndpointCondition.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2012-2017 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.boot.actuate.autoconfigure.endpoint;
+
+import org.springframework.boot.actuate.autoconfigure.endpoint.support.EndpointEnablement;
+import org.springframework.boot.actuate.autoconfigure.endpoint.support.EndpointEnablementProvider;
+import org.springframework.boot.autoconfigure.condition.ConditionMessage;
+import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
+import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
+import org.springframework.boot.endpoint.Endpoint;
+import org.springframework.boot.endpoint.EndpointType;
+import org.springframework.boot.endpoint.jmx.JmxEndpointExtension;
+import org.springframework.boot.endpoint.web.WebEndpointExtension;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ConditionContext;
+import org.springframework.core.annotation.AnnotationUtils;
+import org.springframework.core.type.AnnotatedTypeMetadata;
+import org.springframework.core.type.MethodMetadata;
+import org.springframework.util.ClassUtils;
+import org.springframework.util.StringUtils;
+
+/**
+ * A condition that checks if an endpoint is enabled.
+ *
+ * @author Stephane Nicoll
+ * @author Andy Wilkinson
+ */
+class OnEnabledEndpointCondition extends SpringBootCondition {
+
+ @Override
+ public ConditionOutcome getMatchOutcome(ConditionContext context,
+ AnnotatedTypeMetadata metadata) {
+ EndpointAttributes endpoint = getEndpointAttributes(context, metadata);
+ if (!StringUtils.hasText(endpoint.id)) {
+ throw new IllegalStateException("Endpoint id could not be determined");
+ }
+ EndpointEnablementProvider enablementProvider = new EndpointEnablementProvider(
+ context.getEnvironment());
+ EndpointEnablement endpointEnablement = enablementProvider.getEndpointEnablement(
+ endpoint.id, endpoint.enabled, endpoint.endpointType);
+ return new ConditionOutcome(endpointEnablement.isEnabled(),
+ ConditionMessage.forCondition(ConditionalOnEnabledEndpoint.class)
+ .because(endpointEnablement.getReason()));
+ }
+
+ private EndpointAttributes getEndpointAttributes(ConditionContext context,
+ AnnotatedTypeMetadata metadata) {
+ if (metadata instanceof MethodMetadata
+ && metadata.isAnnotated(Bean.class.getName())) {
+ MethodMetadata methodMetadata = (MethodMetadata) metadata;
+ try {
+ // We should be safe to load at this point since we are in the
+ // REGISTER_BEAN phase
+ Class> returnType = ClassUtils.forName(
+ methodMetadata.getReturnTypeName(), context.getClassLoader());
+ return extractEndpointAttributes(returnType);
+ }
+ catch (Throwable ex) {
+ throw new IllegalStateException("Failed to extract endpoint id for "
+ + methodMetadata.getDeclaringClassName() + "."
+ + methodMetadata.getMethodName(), ex);
+ }
+ }
+ throw new IllegalStateException(
+ "OnEnabledEndpointCondition may only be used on @Bean methods");
+ }
+
+ protected EndpointAttributes extractEndpointAttributes(Class> type) {
+ EndpointAttributes attributes = extractEndpointAttributesFromEndpoint(type);
+ if (attributes != null) {
+ return attributes;
+ }
+ JmxEndpointExtension jmxExtension = AnnotationUtils.findAnnotation(type,
+ JmxEndpointExtension.class);
+ if (jmxExtension != null) {
+ return extractEndpointAttributes(jmxExtension.endpoint());
+ }
+ WebEndpointExtension webExtension = AnnotationUtils.findAnnotation(type,
+ WebEndpointExtension.class);
+ if (webExtension != null) {
+ return extractEndpointAttributes(webExtension.endpoint());
+ }
+ throw new IllegalStateException(
+ "OnEnabledEndpointCondition may only be used on @Bean methods that return"
+ + " @Endpoint, @JmxEndpointExtension, or @WebEndpointExtension");
+ }
+
+ private EndpointAttributes extractEndpointAttributesFromEndpoint(
+ Class> endpointClass) {
+ Endpoint endpoint = AnnotationUtils.findAnnotation(endpointClass, Endpoint.class);
+ if (endpoint == null) {
+ return null;
+ }
+ // If both types are set, all techs are exposed
+ EndpointType endpointType = (endpoint.types().length == 1 ? endpoint.types()[0]
+ : null);
+ return new EndpointAttributes(endpoint.id(), endpoint.enabledByDefault(),
+ endpointType);
+ }
+
+ private static class EndpointAttributes {
+
+ private final String id;
+
+ private final boolean enabled;
+
+ private final EndpointType endpointType;
+
+ EndpointAttributes(String id, boolean enabled, EndpointType endpointType) {
+ this.id = id;
+ this.enabled = enabled;
+ this.endpointType = endpointType;
+ }
+
+ }
+
+}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/ActuatorMediaTypes.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/ActuatorMediaTypes.java
similarity index 94%
rename from spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/ActuatorMediaTypes.java
rename to spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/ActuatorMediaTypes.java
index 6817a398a3..8b4dcfa5e7 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/ActuatorMediaTypes.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/ActuatorMediaTypes.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.springframework.boot.actuate.endpoint.mvc;
+package org.springframework.boot.actuate.autoconfigure.endpoint.infrastructure;
import org.springframework.http.MediaType;
@@ -23,7 +23,7 @@ import org.springframework.http.MediaType;
*
* @author Andy Wilkinson
* @author Madhura Bhave
- * @since 1.5.0
+ * @since 2.0.0
*/
public final class ActuatorMediaTypes {
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/CachingConfigurationFactory.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/CachingConfigurationFactory.java
new file mode 100644
index 0000000000..e7df115776
--- /dev/null
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/CachingConfigurationFactory.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2012-2017 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.boot.actuate.autoconfigure.endpoint.infrastructure;
+
+import java.util.function.Function;
+
+import org.springframework.boot.endpoint.CachingConfiguration;
+import org.springframework.core.env.Environment;
+
+/**
+ * A {@link CachingConfiguration} factory that use the {@link Environment} to extract
+ * the caching settings of each endpoint.
+ *
+ * @author Stephane Nicoll
+ */
+class CachingConfigurationFactory
+ implements Function {
+
+ private final Environment environment;
+
+ /**
+ * Create a new instance with the {@link Environment} to use.
+ * @param environment the environment
+ */
+ CachingConfigurationFactory(Environment environment) {
+ this.environment = environment;
+ }
+
+ @Override
+ public CachingConfiguration apply(String endpointId) {
+ String key = String.format("endpoints.%s.cache.time-to-live", endpointId);
+ Long ttl = this.environment.getProperty(key, Long.class, 0L);
+ return new CachingConfiguration(ttl);
+ }
+}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/DefaultEndpointObjectNameFactory.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/DefaultEndpointObjectNameFactory.java
new file mode 100644
index 0000000000..6bd648e01e
--- /dev/null
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/DefaultEndpointObjectNameFactory.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2012-2017 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.boot.actuate.autoconfigure.endpoint.infrastructure;
+
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.springframework.boot.endpoint.jmx.EndpointMBean;
+import org.springframework.boot.endpoint.jmx.EndpointObjectNameFactory;
+import org.springframework.jmx.support.ObjectNameManager;
+import org.springframework.util.StringUtils;
+
+/**
+ * A {@link EndpointObjectNameFactory} that generates standard {@link ObjectName} for
+ * Actuator's endpoints.
+ *
+ * @author Stephane Nicoll
+ */
+class DefaultEndpointObjectNameFactory implements EndpointObjectNameFactory {
+
+ private String domain = "org.springframework.boot";
+
+ @Override
+ public ObjectName generate(EndpointMBean mBean) throws MalformedObjectNameException {
+ StringBuilder builder = new StringBuilder();
+ builder.append(this.domain);
+ builder.append(":type=Endpoint");
+ builder.append(",name=" + StringUtils.capitalize(mBean.getEndpointId()));
+ return ObjectNameManager.getInstance(builder.toString());
+ }
+
+}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/EndpointInfrastructureAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/EndpointInfrastructureAutoConfiguration.java
new file mode 100644
index 0000000000..9bd3a32bf4
--- /dev/null
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/EndpointInfrastructureAutoConfiguration.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2012-2017 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.boot.actuate.autoconfigure.endpoint.infrastructure;
+
+import java.time.OffsetDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+
+import javax.management.MBeanServer;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
+import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;
+import org.springframework.boot.endpoint.ConversionServiceOperationParameterMapper;
+import org.springframework.boot.endpoint.EndpointType;
+import org.springframework.boot.endpoint.OperationParameterMapper;
+import org.springframework.boot.endpoint.jmx.EndpointMBeanRegistrar;
+import org.springframework.boot.endpoint.jmx.JmxAnnotationEndpointDiscoverer;
+import org.springframework.boot.endpoint.jmx.JmxEndpointOperation;
+import org.springframework.boot.endpoint.web.WebAnnotationEndpointDiscoverer;
+import org.springframework.boot.endpoint.web.WebEndpointOperation;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.convert.support.DefaultConversionService;
+import org.springframework.util.StringUtils;
+
+/**
+ * {@link EnableAutoConfiguration Auto-configuration} for the endpoint infrastructure used
+ * by the Actuator.
+ *
+ * @author Andy Wilkinson
+ * @author Stephane Nicoll
+ * @since 2.0.0
+ */
+@Configuration
+@AutoConfigureAfter(JmxAutoConfiguration.class)
+public class EndpointInfrastructureAutoConfiguration {
+
+ private final ApplicationContext applicationContext;
+
+ public EndpointInfrastructureAutoConfiguration(
+ ApplicationContext applicationContext) {
+ this.applicationContext = applicationContext;
+ }
+
+ @Bean
+ public OperationParameterMapper operationParameterMapper() {
+ DefaultConversionService conversionService = new DefaultConversionService();
+ conversionService.addConverter(String.class, Date.class, (string) -> {
+ if (StringUtils.hasLength(string)) {
+ OffsetDateTime offsetDateTime = OffsetDateTime.parse(string,
+ DateTimeFormatter.ISO_OFFSET_DATE_TIME);
+ return new Date(offsetDateTime.toEpochSecond() * 1000);
+ }
+ return null;
+ });
+ return new ConversionServiceOperationParameterMapper(conversionService);
+ }
+
+ @Bean
+ public CachingConfigurationFactory cacheConfigurationFactory() {
+ return new CachingConfigurationFactory(this.applicationContext.getEnvironment());
+ }
+
+ @Bean
+ public JmxAnnotationEndpointDiscoverer jmxEndpointDiscoverer(
+ OperationParameterMapper operationParameterMapper,
+ CachingConfigurationFactory cachingConfigurationFactory) {
+ return new JmxAnnotationEndpointDiscoverer(this.applicationContext,
+ operationParameterMapper, cachingConfigurationFactory);
+ }
+
+ @ConditionalOnSingleCandidate(MBeanServer.class)
+ @Bean
+ public JmxEndpointExporter jmxMBeanExporter(MBeanServer mBeanServer,
+ JmxAnnotationEndpointDiscoverer endpointDiscoverer,
+ ObjectProvider objectMapper) {
+ EndpointProvider endpointProvider = new EndpointProvider<>(
+ this.applicationContext.getEnvironment(), endpointDiscoverer,
+ EndpointType.JMX);
+ EndpointMBeanRegistrar endpointMBeanRegistrar = new EndpointMBeanRegistrar(
+ mBeanServer, new DefaultEndpointObjectNameFactory());
+ return new JmxEndpointExporter(endpointProvider, endpointMBeanRegistrar,
+ objectMapper.getIfAvailable(ObjectMapper::new));
+ }
+
+ @ConditionalOnWebApplication
+ static class WebInfrastructureConfiguration {
+
+ private final ApplicationContext applicationContext;
+
+ WebInfrastructureConfiguration(ApplicationContext applicationContext) {
+ this.applicationContext = applicationContext;
+ }
+
+ @Bean
+ public EndpointProvider webEndpointProvider(
+ OperationParameterMapper operationParameterMapper,
+ CachingConfigurationFactory cachingConfigurationFactory) {
+ return new EndpointProvider<>(this.applicationContext.getEnvironment(),
+ webEndpointDiscoverer(operationParameterMapper,
+ cachingConfigurationFactory),
+ EndpointType.WEB);
+ }
+
+ private WebAnnotationEndpointDiscoverer webEndpointDiscoverer(
+ OperationParameterMapper operationParameterMapper,
+ CachingConfigurationFactory cachingConfigurationFactory) {
+ List mediaTypes = Arrays.asList(
+ ActuatorMediaTypes.APPLICATION_ACTUATOR_V2_JSON_VALUE,
+ "application/json");
+ return new WebAnnotationEndpointDiscoverer(this.applicationContext,
+ operationParameterMapper, cachingConfigurationFactory, mediaTypes,
+ mediaTypes);
+ }
+
+ }
+
+}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/EndpointProvider.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/EndpointProvider.java
new file mode 100644
index 0000000000..ab7eb14f56
--- /dev/null
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/EndpointProvider.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2012-2017 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.boot.actuate.autoconfigure.endpoint.infrastructure;
+
+import java.util.Collection;
+import java.util.stream.Collectors;
+
+import org.springframework.boot.actuate.autoconfigure.endpoint.support.EndpointEnablementProvider;
+import org.springframework.boot.endpoint.EndpointDiscoverer;
+import org.springframework.boot.endpoint.EndpointInfo;
+import org.springframework.boot.endpoint.EndpointOperation;
+import org.springframework.boot.endpoint.EndpointType;
+import org.springframework.core.env.Environment;
+
+/**
+ * Provides the endpoints that are enabled according to an {@link EndpointDiscoverer} and
+ * the current {@link Environment}.
+ *
+ * @param the endpoint operation type
+ * @author Stephane Nicoll
+ * @since 2.0.0
+ */
+public final class EndpointProvider {
+
+ private final EndpointDiscoverer discoverer;
+
+ private final EndpointEnablementProvider endpointEnablementProvider;
+
+ private final EndpointType endpointType;
+
+ /**
+ * Creates a new instance.
+ * @param environment the environment to use to check the endpoints that are enabled
+ * @param discoverer the discoverer to get the initial set of endpoints
+ * @param endpointType the type of endpoint to handle
+ */
+ public EndpointProvider(Environment environment, EndpointDiscoverer discoverer,
+ EndpointType endpointType) {
+ this.discoverer = discoverer;
+ this.endpointEnablementProvider = new EndpointEnablementProvider(environment);
+ this.endpointType = endpointType;
+ }
+
+ public Collection> getEndpoints() {
+ return this.discoverer.discoverEndpoints().stream().filter(this::isEnabled)
+ .collect(Collectors.toList());
+ }
+
+ private boolean isEnabled(EndpointInfo> endpoint) {
+ return this.endpointEnablementProvider.getEndpointEnablement(endpoint.getId(),
+ endpoint.isEnabledByDefault(), this.endpointType).isEnabled();
+ }
+
+}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/JmxEndpointExporter.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/JmxEndpointExporter.java
new file mode 100644
index 0000000000..d1a4e2b04c
--- /dev/null
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/JmxEndpointExporter.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2012-2017 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.boot.actuate.autoconfigure.endpoint.infrastructure;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import com.fasterxml.jackson.databind.JavaType;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.boot.endpoint.Endpoint;
+import org.springframework.boot.endpoint.jmx.EndpointMBean;
+import org.springframework.boot.endpoint.jmx.EndpointMBeanRegistrar;
+import org.springframework.boot.endpoint.jmx.JmxEndpointMBeanFactory;
+import org.springframework.boot.endpoint.jmx.JmxEndpointOperation;
+import org.springframework.boot.endpoint.jmx.JmxOperationResponseMapper;
+
+/**
+ * Exports all available {@link Endpoint} to a configurable {@link MBeanServer}.
+ *
+ * @author Stephane Nicoll
+ * @since 2.0.0
+ */
+class JmxEndpointExporter implements InitializingBean, DisposableBean {
+
+ private final EndpointProvider endpointProvider;
+
+ private final EndpointMBeanRegistrar endpointMBeanRegistrar;
+
+ private final JmxEndpointMBeanFactory mBeanFactory;
+
+ private Collection registeredObjectNames;
+
+ JmxEndpointExporter(EndpointProvider endpointProvider,
+ EndpointMBeanRegistrar endpointMBeanRegistrar,
+ ObjectMapper objectMapper) {
+ this.endpointProvider = endpointProvider;
+ this.endpointMBeanRegistrar = endpointMBeanRegistrar;
+ DataConverter dataConverter = new DataConverter(objectMapper);
+ this.mBeanFactory = new JmxEndpointMBeanFactory(dataConverter);
+ }
+
+ @Override
+ public void afterPropertiesSet() {
+ this.registeredObjectNames = registerEndpointMBeans();
+ }
+
+ @Override
+ public void destroy() throws Exception {
+ unregisterEndpointMBeans(this.registeredObjectNames);
+ }
+
+ private Collection registerEndpointMBeans() {
+ List objectNames = new ArrayList<>();
+ Collection mBeans = this.mBeanFactory.createMBeans(
+ this.endpointProvider.getEndpoints());
+ for (EndpointMBean mBean : mBeans) {
+ objectNames.add(this.endpointMBeanRegistrar.registerEndpointMBean(mBean));
+ }
+ return objectNames;
+ }
+
+ private void unregisterEndpointMBeans(Collection objectNames) {
+ objectNames.forEach(this.endpointMBeanRegistrar::unregisterEndpointMbean);
+
+ }
+
+ static class DataConverter implements JmxOperationResponseMapper {
+
+ private final ObjectMapper objectMapper;
+
+ private final JavaType listObject;
+
+ private final JavaType mapStringObject;
+
+ DataConverter(ObjectMapper objectMapper) {
+ this.objectMapper = (objectMapper == null ? new ObjectMapper()
+ : objectMapper);
+ this.listObject = this.objectMapper.getTypeFactory()
+ .constructParametricType(List.class, Object.class);
+ this.mapStringObject = this.objectMapper.getTypeFactory()
+ .constructParametricType(Map.class, String.class, Object.class);
+ }
+
+ @Override
+ public Object mapResponse(Object response) {
+ if (response == null) {
+ return null;
+ }
+ if (response instanceof String) {
+ return response;
+ }
+ if (response.getClass().isArray() || response instanceof Collection) {
+ return this.objectMapper.convertValue(response, this.listObject);
+ }
+ return this.objectMapper.convertValue(response, this.mapStringObject);
+ }
+
+ @Override
+ public Class> mapResponseType(Class> responseType) {
+ if (responseType.equals(String.class)) {
+ return String.class;
+ }
+ if (responseType.isArray() || Collection.class.isAssignableFrom(responseType)) {
+ return List.class;
+ }
+ return Map.class;
+ }
+
+
+ }
+
+}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/ManagementWebServerFactoryCustomizer.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/ManagementWebServerFactoryCustomizer.java
new file mode 100644
index 0000000000..3527e82c06
--- /dev/null
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/ManagementWebServerFactoryCustomizer.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2012-2017 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.boot.actuate.autoconfigure.endpoint.infrastructure;
+
+import java.util.Collections;
+
+import org.springframework.beans.factory.BeanFactoryUtils;
+import org.springframework.beans.factory.ListableBeanFactory;
+import org.springframework.boot.actuate.autoconfigure.web.ManagementServerProperties;
+import org.springframework.boot.autoconfigure.web.ServerProperties;
+import org.springframework.boot.web.server.ConfigurableWebServerFactory;
+import org.springframework.boot.web.server.ErrorPage;
+import org.springframework.boot.web.server.Ssl;
+import org.springframework.boot.web.server.WebServerFactory;
+import org.springframework.boot.web.server.WebServerFactoryCustomizer;
+import org.springframework.core.Ordered;
+
+/**
+ * {@link WebServerFactoryCustomizer} that customizes the {@link WebServerFactory} used to
+ * create the management context's web server.
+ *
+ * @param the type of web server factory to customize
+ * @author Andy Wilkinson
+ */
+abstract class ManagementWebServerFactoryCustomizer
+ implements WebServerFactoryCustomizer, Ordered {
+
+ private final ListableBeanFactory beanFactory;
+
+ private final Class extends WebServerFactoryCustomizer> customizerClass;
+
+ protected ManagementWebServerFactoryCustomizer(ListableBeanFactory beanFactory,
+ Class extends WebServerFactoryCustomizer> customizerClass) {
+ this.beanFactory = beanFactory;
+ this.customizerClass = customizerClass;
+ }
+
+ @Override
+ public int getOrder() {
+ return 0;
+ }
+
+ @Override
+ public final void customize(T webServerFactory) {
+ ManagementServerProperties managementServerProperties = BeanFactoryUtils
+ .beanOfTypeIncludingAncestors(this.beanFactory,
+ ManagementServerProperties.class);
+ ServerProperties serverProperties = BeanFactoryUtils
+ .beanOfTypeIncludingAncestors(this.beanFactory, ServerProperties.class);
+ WebServerFactoryCustomizer webServerFactoryCustomizer = BeanFactoryUtils
+ .beanOfTypeIncludingAncestors(this.beanFactory, this.customizerClass);
+ // Customize as per the parent context first (so e.g. the access logs go to
+ // the same place)
+ webServerFactoryCustomizer.customize(webServerFactory);
+ // Then reset the error pages
+ webServerFactory.setErrorPages(Collections.emptySet());
+ // and add the management-specific bits
+ customize(webServerFactory, managementServerProperties, serverProperties);
+ }
+
+ protected void customize(T webServerFactory,
+ ManagementServerProperties managementServerProperties,
+ ServerProperties serverProperties) {
+ webServerFactory.setPort(managementServerProperties.getPort());
+ Ssl ssl = managementServerProperties.getSsl();
+ if (ssl != null) {
+ webServerFactory.setSsl(ssl);
+ }
+ webServerFactory.setServerHeader(serverProperties.getServerHeader());
+ webServerFactory.setAddress(managementServerProperties.getAddress());
+ webServerFactory
+ .addErrorPages(new ErrorPage(serverProperties.getError().getPath()));
+ }
+
+}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/ReactiveEndpointChildManagementContextConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/ReactiveEndpointChildManagementContextConfiguration.java
new file mode 100644
index 0000000000..41596f9c37
--- /dev/null
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/ReactiveEndpointChildManagementContextConfiguration.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2012-2017 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.boot.actuate.autoconfigure.endpoint.infrastructure;
+
+import org.springframework.beans.factory.ListableBeanFactory;
+import org.springframework.boot.actuate.autoconfigure.ManagementContextConfiguration;
+import org.springframework.boot.actuate.autoconfigure.ManagementContextType;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
+import org.springframework.boot.autoconfigure.web.reactive.DefaultReactiveWebServerCustomizer;
+import org.springframework.boot.web.reactive.server.ConfigurableReactiveWebServerFactory;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.http.server.reactive.HttpHandler;
+import org.springframework.web.reactive.config.EnableWebFlux;
+import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
+
+/**
+ * Configuration for reactive web endpoint infrastructure when a separate management
+ * context with a web server running on a different port is required.
+ *
+ * @author Andy Wilkinson
+ */
+@EnableWebFlux
+@ManagementContextConfiguration(ManagementContextType.CHILD)
+@ConditionalOnWebApplication(type = Type.REACTIVE)
+class ReactiveEndpointChildManagementContextConfiguration {
+
+ @Bean
+ public HttpHandler httpHandler(ApplicationContext applicationContext) {
+ return WebHttpHandlerBuilder.applicationContext(applicationContext).build();
+ }
+
+ @Bean
+ public ManagementReactiveWebServerFactoryCustomizer webServerFactoryCustomizer(
+ ListableBeanFactory beanFactory) {
+ return new ManagementReactiveWebServerFactoryCustomizer(beanFactory);
+ }
+
+ static class ManagementReactiveWebServerFactoryCustomizer extends
+ ManagementWebServerFactoryCustomizer {
+
+ ManagementReactiveWebServerFactoryCustomizer(ListableBeanFactory beanFactory) {
+ super(beanFactory, DefaultReactiveWebServerCustomizer.class);
+ }
+
+ }
+
+}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/ServletEndpointAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/ServletEndpointAutoConfiguration.java
new file mode 100644
index 0000000000..2bc92539af
--- /dev/null
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/ServletEndpointAutoConfiguration.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2012-2017 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.boot.actuate.autoconfigure.endpoint.infrastructure;
+
+import javax.servlet.Servlet;
+
+import org.springframework.boot.actuate.autoconfigure.endpoint.ManagementContextResolver;
+import org.springframework.boot.actuate.autoconfigure.web.ManagementServerProperties;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
+import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
+import org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration;
+import org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration;
+import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
+import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
+import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.boot.web.servlet.filter.ApplicationContextHeaderFilter;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * {@link EnableAutoConfiguration Auto-configuration} for Servlet-specific endpoint
+ * concerns.
+ *
+ * @author Dave Syer
+ * @author Phillip Webb
+ * @author Christian Dupuis
+ * @author Andy Wilkinson
+ * @author Johannes Edmeier
+ * @author EddĂș MelĂ©ndez
+ * @author Venil Noronha
+ * @author Madhura Bhave
+ */
+@Configuration
+@ConditionalOnClass(Servlet.class)
+@ConditionalOnWebApplication(type = Type.SERVLET)
+@EnableConfigurationProperties(ManagementServerProperties.class)
+@AutoConfigureAfter({ PropertyPlaceholderAutoConfiguration.class,
+ ServletWebServerFactoryAutoConfiguration.class, WebMvcAutoConfiguration.class,
+ RepositoryRestMvcAutoConfiguration.class, HypermediaAutoConfiguration.class,
+ HttpMessageConvertersAutoConfiguration.class,
+ EndpointInfrastructureAutoConfiguration.class })
+public class ServletEndpointAutoConfiguration {
+
+ @Bean
+ public ManagementContextResolver managementContextResolver(
+ ApplicationContext applicationContext) {
+ return new ManagementContextResolver(applicationContext);
+ }
+
+ // Put Servlets and Filters in their own nested class so they don't force early
+ // instantiation of ManagementServerProperties.
+ @Configuration
+ @ConditionalOnProperty(prefix = "management", name = "add-application-context-header", havingValue = "true")
+ protected static class ApplicationContextFilterConfiguration {
+
+ @Bean
+ public ApplicationContextHeaderFilter applicationContextIdFilter(
+ ApplicationContext context) {
+ return new ApplicationContextHeaderFilter(context);
+ }
+
+ }
+
+}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/EndpointWebMvcChildContextConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/ServletEndpointChildManagementContextConfiguration.java
similarity index 61%
rename from spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/EndpointWebMvcChildContextConfiguration.java
rename to spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/ServletEndpointChildManagementContextConfiguration.java
index fda7a8db65..d580f8de2c 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/EndpointWebMvcChildContextConfiguration.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/ServletEndpointChildManagementContextConfiguration.java
@@ -14,10 +14,9 @@
* limitations under the License.
*/
-package org.springframework.boot.actuate.autoconfigure.endpoint;
+package org.springframework.boot.actuate.autoconfigure.endpoint.infrastructure;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import javax.servlet.Filter;
@@ -26,38 +25,37 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.catalina.Valve;
import org.apache.catalina.valves.AccessLogValve;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.servlet.ServletContainer;
import org.springframework.beans.factory.BeanFactory;
-import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.HierarchicalBeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.actuate.autoconfigure.ManagementContextConfiguration;
+import org.springframework.boot.actuate.autoconfigure.ManagementContextType;
import org.springframework.boot.actuate.autoconfigure.web.ManagementServerProperties;
-import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping;
import org.springframework.boot.actuate.endpoint.mvc.ManagementErrorEndpoint;
-import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
-import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoints;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
-import org.springframework.boot.autoconfigure.hateoas.HypermediaHttpMessageConverterConfiguration;
+import org.springframework.boot.autoconfigure.jersey.ResourceConfigCustomizer;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.servlet.DefaultServletWebServerFactoryCustomizer;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorAttributes;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory;
-import org.springframework.boot.web.server.ErrorPage;
-import org.springframework.boot.web.server.WebServer;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
+import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.Import;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
-import org.springframework.hateoas.LinkDiscoverer;
-import org.springframework.hateoas.config.EnableHypermediaSupport;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.HandlerAdapter;
@@ -68,50 +66,23 @@ import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
/**
- * Configuration triggered from {@link EndpointWebMvcAutoConfiguration} when a new
- * {@link WebServer} running on a different port is required.
+ * Configuration for Servlet web endpoint infrastructure when a separate management
+ * context with a web server running on a different port is required.
*
* @author Dave Syer
* @author Stephane Nicoll
* @author Andy Wilkinson
* @author EddĂș MelĂ©ndez
- * @see EndpointWebMvcAutoConfiguration
- * @since 2.0.0
*/
@Configuration
-@EnableWebMvc
-@Import(ManagementContextConfigurationsImportSelector.class)
-public class EndpointWebMvcChildContextConfiguration {
-
- @Bean(name = DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
- public DispatcherServlet dispatcherServlet() {
- DispatcherServlet dispatcherServlet = new DispatcherServlet();
- // Ensure the parent configuration does not leak down to us
- dispatcherServlet.setDetectAllHandlerAdapters(false);
- dispatcherServlet.setDetectAllHandlerExceptionResolvers(false);
- dispatcherServlet.setDetectAllHandlerMappings(false);
- dispatcherServlet.setDetectAllViewResolvers(false);
- return dispatcherServlet;
- }
-
- @Bean(name = DispatcherServlet.HANDLER_MAPPING_BEAN_NAME)
- public CompositeHandlerMapping compositeHandlerMapping() {
- return new CompositeHandlerMapping();
- }
-
- @Bean(name = DispatcherServlet.HANDLER_ADAPTER_BEAN_NAME)
- public CompositeHandlerAdapter compositeHandlerAdapter() {
- return new CompositeHandlerAdapter();
- }
-
- @Bean(name = DispatcherServlet.HANDLER_EXCEPTION_RESOLVER_BEAN_NAME)
- public CompositeHandlerExceptionResolver compositeHandlerExceptionResolver() {
- return new CompositeHandlerExceptionResolver();
- }
+@ManagementContextConfiguration(ManagementContextType.CHILD)
+@ConditionalOnWebApplication(type = Type.SERVLET)
+class ServletEndpointChildManagementContextConfiguration {
@Bean
- public ServerFactoryCustomization serverCustomization() {
- return new ServerFactoryCustomization();
+ public ManagementServletWebServerFactoryCustomization serverCustomization(
+ ListableBeanFactory beanFactory) {
+ return new ManagementServletWebServerFactoryCustomization(beanFactory);
}
@Bean
@@ -125,28 +96,75 @@ public class EndpointWebMvcChildContextConfiguration {
return new TomcatAccessLogCustomizer();
}
- /*
- * The error controller is present but not mapped as an endpoint in this context
- * because of the DispatcherServlet having had its HandlerMapping explicitly disabled.
- * So we expose the same feature but only for machine endpoints.
- */
- @Bean
- @ConditionalOnBean(ErrorAttributes.class)
- public ManagementErrorEndpoint errorEndpoint(ErrorAttributes errorAttributes) {
- return new ManagementErrorEndpoint(errorAttributes);
+ @EnableWebMvc
+ @ConditionalOnClass(DispatcherServlet.class)
+ static class MvcEndpointChildContextConfiguration {
+
+ /*
+ * The error controller is present but not mapped as an endpoint in this context
+ * because of the DispatcherServlet having had its HandlerMapping explicitly
+ * disabled. So we expose the same feature but only for machine endpoints.
+ */
+ @Bean
+ @ConditionalOnBean(ErrorAttributes.class)
+ public ManagementErrorEndpoint errorEndpoint(ErrorAttributes errorAttributes) {
+ return new ManagementErrorEndpoint(errorAttributes);
+ }
+
+ @Bean(name = DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
+ public DispatcherServlet dispatcherServlet() {
+ DispatcherServlet dispatcherServlet = new DispatcherServlet();
+ // Ensure the parent configuration does not leak down to us
+ dispatcherServlet.setDetectAllHandlerAdapters(false);
+ dispatcherServlet.setDetectAllHandlerExceptionResolvers(false);
+ dispatcherServlet.setDetectAllHandlerMappings(false);
+ dispatcherServlet.setDetectAllViewResolvers(false);
+ return dispatcherServlet;
+ }
+
+ @Bean(name = DispatcherServlet.HANDLER_MAPPING_BEAN_NAME)
+ public CompositeHandlerMapping compositeHandlerMapping() {
+ return new CompositeHandlerMapping();
+ }
+
+ @Bean(name = DispatcherServlet.HANDLER_ADAPTER_BEAN_NAME)
+ public CompositeHandlerAdapter compositeHandlerAdapter() {
+ return new CompositeHandlerAdapter();
+ }
+
+ @Bean(name = DispatcherServlet.HANDLER_EXCEPTION_RESOLVER_BEAN_NAME)
+ public CompositeHandlerExceptionResolver compositeHandlerExceptionResolver() {
+ return new CompositeHandlerExceptionResolver();
+ }
+
}
- /**
- * Configuration to add {@link HandlerMapping} for {@link MvcEndpoint}s.
- */
@Configuration
- protected static class EndpointHandlerMappingConfiguration {
+ @ConditionalOnClass(ResourceConfig.class)
+ @ConditionalOnMissingClass("org.springframework.web.servlet.DispatcherServlet")
+ static class JerseyEndpointChildContextConfiguration {
- @Autowired
- public void handlerMapping(MvcEndpoints endpoints,
- ListableBeanFactory beanFactory, EndpointHandlerMapping mapping) {
- // In a child context we definitely want to see the parent endpoints
- mapping.setDetectHandlerMethodsInAncestorContexts(true);
+ private final List resourceConfigCustomizers;
+
+ JerseyEndpointChildContextConfiguration(
+ List resourceConfigCustomizers) {
+ this.resourceConfigCustomizers = resourceConfigCustomizers;
+ }
+
+ @Bean
+ public ServletRegistrationBean jerseyServletRegistration() {
+ ServletRegistrationBean registration = new ServletRegistrationBean<>(
+ new ServletContainer(endpointResourceConfig()), "/*");
+ return registration;
+ }
+
+ @Bean
+ public ResourceConfig endpointResourceConfig() {
+ ResourceConfig resourceConfig = new ResourceConfig();
+ for (ResourceConfigCustomizer customizer : this.resourceConfigCustomizers) {
+ customizer.customize(resourceConfig);
+ }
+ return resourceConfig;
}
}
@@ -154,7 +172,7 @@ public class EndpointWebMvcChildContextConfiguration {
@Configuration
@ConditionalOnClass({ EnableWebSecurity.class, Filter.class })
@ConditionalOnBean(name = "springSecurityFilterChain", search = SearchStrategy.ANCESTORS)
- public static class EndpointWebMvcChildContextSecurityConfiguration {
+ static class EndpointWebMvcChildContextSecurityConfiguration {
@Bean
public Filter springSecurityFilterChain(HierarchicalBeanFactory beanFactory) {
@@ -164,60 +182,20 @@ public class EndpointWebMvcChildContextConfiguration {
}
- @Configuration
- @ConditionalOnClass({ LinkDiscoverer.class })
- @Import(HypermediaHttpMessageConverterConfiguration.class)
- @EnableHypermediaSupport(type = EnableHypermediaSupport.HypermediaType.HAL)
- static class HypermediaConfiguration {
+ static class ManagementServletWebServerFactoryCustomization extends
+ ManagementWebServerFactoryCustomizer {
- }
-
- static class ServerFactoryCustomization implements
- WebServerFactoryCustomizer, Ordered {
-
- @Autowired
- private ListableBeanFactory beanFactory;
-
- // This needs to be lazily initialized because web server customizer
- // instances get their callback very early in the context lifecycle.
- private ManagementServerProperties managementServerProperties;
-
- private ServerProperties server;
-
- private DefaultServletWebServerFactoryCustomizer serverCustomizer;
-
- @Override
- public int getOrder() {
- return 0;
+ ManagementServletWebServerFactoryCustomization(ListableBeanFactory beanFactory) {
+ super(beanFactory, DefaultServletWebServerFactoryCustomizer.class);
}
@Override
- public void customize(ConfigurableServletWebServerFactory webServerFactory) {
- if (this.managementServerProperties == null) {
- this.managementServerProperties = BeanFactoryUtils
- .beanOfTypeIncludingAncestors(this.beanFactory,
- ManagementServerProperties.class);
- this.server = BeanFactoryUtils.beanOfTypeIncludingAncestors(
- this.beanFactory, ServerProperties.class);
- this.serverCustomizer = BeanFactoryUtils.beanOfTypeIncludingAncestors(
- this.beanFactory, DefaultServletWebServerFactoryCustomizer.class);
- }
- // Customize as per the parent context first (so e.g. the access logs go to
- // the same place)
- this.serverCustomizer.customize(webServerFactory);
- // Then reset the error pages
- webServerFactory.setErrorPages(Collections.emptySet());
- // and the context path
+ protected void customize(ConfigurableServletWebServerFactory webServerFactory,
+ ManagementServerProperties managementServerProperties,
+ ServerProperties serverProperties) {
+ super.customize(webServerFactory, managementServerProperties,
+ serverProperties);
webServerFactory.setContextPath("");
- // and add the management-specific bits
- webServerFactory.setPort(this.managementServerProperties.getPort());
- if (this.managementServerProperties.getSsl() != null) {
- webServerFactory.setSsl(this.managementServerProperties.getSsl());
- }
- webServerFactory.setServerHeader(this.server.getServerHeader());
- webServerFactory.setAddress(this.managementServerProperties.getAddress());
- webServerFactory
- .addErrorPages(new ErrorPage(this.server.getError().getPath()));
}
}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/WebEndpointHandlerMappingCustomizer.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/WebEndpointHandlerMappingCustomizer.java
new file mode 100644
index 0000000000..18dd8b9341
--- /dev/null
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/WebEndpointHandlerMappingCustomizer.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2012-2017 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.boot.actuate.autoconfigure.endpoint.infrastructure;
+
+import org.springframework.boot.endpoint.web.mvc.WebEndpointServletHandlerMapping;
+
+/**
+ * Callback for customizing the {@link WebEndpointServletHandlerMapping} at configuration
+ * time.
+ *
+ * @author Andy Wilkinson
+ * @since 2.0.0
+ */
+@FunctionalInterface
+public interface WebEndpointHandlerMappingCustomizer {
+
+ /**
+ * Customize the given {@code mapping}.
+ * @param mapping the mapping to customize
+ */
+ void customize(WebEndpointServletHandlerMapping mapping);
+
+}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/WebEndpointInfrastructureManagementContextConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/WebEndpointInfrastructureManagementContextConfiguration.java
new file mode 100644
index 0000000000..8e687c7b65
--- /dev/null
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/WebEndpointInfrastructureManagementContextConfiguration.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2012-2017 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.boot.actuate.autoconfigure.endpoint.infrastructure;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+
+import org.glassfish.jersey.server.ResourceConfig;
+
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.boot.actuate.autoconfigure.ManagementContextConfiguration;
+import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointCorsProperties;
+import org.springframework.boot.actuate.autoconfigure.web.ManagementServerProperties;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
+import org.springframework.boot.autoconfigure.jersey.ResourceConfigCustomizer;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.boot.endpoint.web.WebEndpointOperation;
+import org.springframework.boot.endpoint.web.jersey.JerseyEndpointResourceFactory;
+import org.springframework.boot.endpoint.web.mvc.WebEndpointServletHandlerMapping;
+import org.springframework.boot.endpoint.web.reactive.WebEndpointReactiveHandlerMapping;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.util.CollectionUtils;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.servlet.DispatcherServlet;
+
+/**
+ * Management context configuration for the infrastructure for web endpoints.
+ *
+ * @author Andy Wilkinson
+ */
+@ConditionalOnWebApplication
+@ManagementContextConfiguration
+@EnableConfigurationProperties({ EndpointCorsProperties.class,
+ ManagementServerProperties.class })
+class WebEndpointInfrastructureManagementContextConfiguration {
+
+ @Configuration
+ @ConditionalOnWebApplication(type = Type.SERVLET)
+ @ConditionalOnClass(ResourceConfig.class)
+ @ConditionalOnBean(ResourceConfig.class)
+ @ConditionalOnMissingBean(type = "org.springframework.web.servlet.DispatcherServlet")
+ static class JerseyWebEndpointConfiguration {
+
+ @Bean
+ public ResourceConfigCustomizer webEndpointRegistrar(
+ EndpointProvider provider,
+ ManagementServerProperties managementServerProperties) {
+ return (resourceConfig) -> resourceConfig.registerResources(new HashSet<>(
+ new JerseyEndpointResourceFactory().createEndpointResources(
+ managementServerProperties.getContextPath(),
+ provider.getEndpoints())));
+ }
+
+ }
+
+ @Configuration
+ @ConditionalOnWebApplication(type = Type.SERVLET)
+ @ConditionalOnClass(DispatcherServlet.class)
+ @ConditionalOnBean(DispatcherServlet.class)
+ static class MvcWebEndpointConfiguration {
+
+ private final List mappingCustomizers;
+
+ MvcWebEndpointConfiguration(
+ ObjectProvider> mappingCustomizers) {
+ this.mappingCustomizers = mappingCustomizers
+ .getIfUnique(Collections::emptyList);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public WebEndpointServletHandlerMapping webEndpointServletHandlerMapping(
+ EndpointProvider provider,
+ EndpointCorsProperties corsProperties,
+ ManagementServerProperties managementServerProperties) {
+ WebEndpointServletHandlerMapping handlerMapping = new WebEndpointServletHandlerMapping(
+ managementServerProperties.getContextPath(), provider.getEndpoints(),
+ getCorsConfiguration(corsProperties));
+ for (WebEndpointHandlerMappingCustomizer customizer : this.mappingCustomizers) {
+ customizer.customize(handlerMapping);
+ }
+ return handlerMapping;
+ }
+
+ private CorsConfiguration getCorsConfiguration(
+ EndpointCorsProperties properties) {
+ if (CollectionUtils.isEmpty(properties.getAllowedOrigins())) {
+ return null;
+ }
+ CorsConfiguration configuration = new CorsConfiguration();
+ configuration.setAllowedOrigins(properties.getAllowedOrigins());
+ if (!CollectionUtils.isEmpty(properties.getAllowedHeaders())) {
+ configuration.setAllowedHeaders(properties.getAllowedHeaders());
+ }
+ if (!CollectionUtils.isEmpty(properties.getAllowedMethods())) {
+ configuration.setAllowedMethods(properties.getAllowedMethods());
+ }
+ if (!CollectionUtils.isEmpty(properties.getExposedHeaders())) {
+ configuration.setExposedHeaders(properties.getExposedHeaders());
+ }
+ if (properties.getMaxAge() != null) {
+ configuration.setMaxAge(properties.getMaxAge());
+ }
+ if (properties.getAllowCredentials() != null) {
+ configuration.setAllowCredentials(properties.getAllowCredentials());
+ }
+ return configuration;
+ }
+
+ }
+
+ @ConditionalOnWebApplication(type = Type.REACTIVE)
+ static class ReactiveWebEndpointConfiguration {
+
+ @Bean
+ @ConditionalOnMissingBean
+ public WebEndpointReactiveHandlerMapping webEndpointReactiveHandlerMapping(
+ EndpointProvider provider,
+ ManagementServerProperties managementServerProperties) {
+ return new WebEndpointReactiveHandlerMapping(
+ managementServerProperties.getContextPath(), provider.getEndpoints());
+ }
+
+ }
+
+}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/package-info.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/package-info.java
new file mode 100644
index 0000000000..41a0bc3f57
--- /dev/null
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2012-2015 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.
+ */
+
+/**
+ * {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
+ * Auto-configuration} for the Actuator's endpoint infrastructure.
+ */
+package org.springframework.boot.actuate.autoconfigure.endpoint.infrastructure;
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/JmxEndpointAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/JmxEndpointAutoConfiguration.java
new file mode 100644
index 0000000000..34e15dde15
--- /dev/null
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/JmxEndpointAutoConfiguration.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2012-2017 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.boot.actuate.autoconfigure.endpoint.jmx;
+
+import org.springframework.boot.actuate.autoconfigure.endpoint.ConditionalOnEnabledEndpoint;
+import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
+import org.springframework.boot.actuate.endpoint.AuditEventsEndpoint;
+import org.springframework.boot.actuate.endpoint.jmx.AuditEventsJmxEndpointExtension;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.endpoint.jmx.JmxEndpointExtension;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * Auto-configuration for JMX {@link org.springframework.boot.endpoint.Endpoint Endpoints}
+ * and JMX-specific {@link JmxEndpointExtension endpoint extensions}.
+ *
+ * @author Andy Wilkinson
+ * @since 2.0.0
+ */
+@AutoConfigureAfter(EndpointAutoConfiguration.class)
+@Configuration
+public class JmxEndpointAutoConfiguration {
+
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnEnabledEndpoint
+ @ConditionalOnBean(AuditEventsEndpoint.class)
+ public AuditEventsJmxEndpointExtension auditEventsJmxEndpointExtension(
+ AuditEventsEndpoint auditEventsEndpoint) {
+ return new AuditEventsJmxEndpointExtension(auditEventsEndpoint);
+ }
+
+}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/jolokia/package-info.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/package-info.java
similarity index 69%
rename from spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/jolokia/package-info.java
rename to spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/package-info.java
index dfabe73189..81e2f4611d 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/jolokia/package-info.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/package-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2017 the original author or authors.
+ * Copyright 2012-2015 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.
@@ -15,6 +15,7 @@
*/
/**
- * Auto-configuration for Jolokia.
+ * {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
+ * Auto-configuration} for the Actuator's JMX endpoints.
*/
-package org.springframework.boot.actuate.autoconfigure.jolokia;
+package org.springframework.boot.actuate.autoconfigure.endpoint.jmx;
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/support/EndpointEnablement.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/support/EndpointEnablement.java
new file mode 100644
index 0000000000..ea4fe14e7a
--- /dev/null
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/support/EndpointEnablement.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2012-2017 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.boot.actuate.autoconfigure.endpoint.support;
+
+/**
+ * Determines if an endpoint is enabled or not.
+ *
+ * @author Stephane Nicoll
+ * @since 2.0.0
+ */
+public final class EndpointEnablement {
+
+ private final boolean enabled;
+ private final String reason;
+
+ /**
+ * Creates a new instance.
+ * @param enabled whether or not the endpoint is enabled
+ * @param reason a human readable reason of the decision
+ */
+ EndpointEnablement(boolean enabled, String reason) {
+ this.enabled = enabled;
+ this.reason = reason;
+ }
+
+ /**
+ * Return whether or not the endpoint is enabled.
+ * @return {@code true} if the endpoint is enabled, {@code false} otherwise
+ */
+ public boolean isEnabled() {
+ return this.enabled;
+ }
+
+ /**
+ * Return a human readable reason of the decision.
+ * @return the reason of the endpoint's enablement
+ */
+ public String getReason() {
+ return this.reason;
+ }
+
+}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/support/EndpointEnablementProvider.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/support/EndpointEnablementProvider.java
new file mode 100644
index 0000000000..65fc6c45d7
--- /dev/null
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/support/EndpointEnablementProvider.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2012-2017 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.boot.actuate.autoconfigure.endpoint.support;
+
+import org.springframework.boot.endpoint.EndpointType;
+import org.springframework.core.env.Environment;
+import org.springframework.util.StringUtils;
+
+/**
+ * Determines an endpoint's enablement based on the current {@link Environment}.
+ *
+ * @author Stephane Nicoll
+ * @since 2.0.0
+ */
+public class EndpointEnablementProvider {
+
+ private final Environment environment;
+
+ /**
+ * Creates a new instance with the {@link Environment} to use.
+ * @param environment the environment
+ */
+ public EndpointEnablementProvider(Environment environment) {
+ this.environment = environment;
+ }
+
+ /**
+ * Return the {@link EndpointEnablement} of an endpoint with no specific tech
+ * exposure.
+ * @param endpointId the id of the endpoint
+ * @param enabledByDefault whether the endpoint is enabled by default or not
+ * @return the {@link EndpointEnablement} of that endpoint
+ */
+ public EndpointEnablement getEndpointEnablement(String endpointId,
+ boolean enabledByDefault) {
+ return getEndpointEnablement(endpointId, enabledByDefault, null);
+ }
+
+ /**
+ * Return the {@link EndpointEnablement} of an endpoint for a specific tech exposure.
+ * @param endpointId the id of the endpoint
+ * @param enabledByDefault whether the endpoint is enabled by default or not
+ * @param endpointType the requested {@link EndpointType}
+ * @return the {@link EndpointEnablement} of that endpoint for the specified {@link EndpointType}
+ */
+ public EndpointEnablement getEndpointEnablement(String endpointId,
+ boolean enabledByDefault, EndpointType endpointType) {
+ if (!StringUtils.hasText(endpointId)) {
+ throw new IllegalArgumentException("Endpoint id must have a value");
+ }
+ if (endpointId.equals("all")) {
+ throw new IllegalArgumentException("Endpoint id 'all' is a reserved value "
+ + "and cannot be used by an endpoint");
+ }
+
+ if (endpointType != null) {
+ String endpointTypeKey = createTechSpecificKey(endpointId, endpointType);
+ EndpointEnablement endpointTypeSpecificOutcome = getEnablementFor(
+ endpointTypeKey);
+ if (endpointTypeSpecificOutcome != null) {
+ return endpointTypeSpecificOutcome;
+ }
+ }
+ else {
+ // If any tech specific is on at this point we should enable the endpoint
+ EndpointEnablement anyTechSpecificOutcome = getAnyTechSpecificOutcomeFor(
+ endpointId);
+ if (anyTechSpecificOutcome != null) {
+ return anyTechSpecificOutcome;
+ }
+ }
+ String endpointKey = createKey(endpointId, "enabled");
+ EndpointEnablement endpointSpecificOutcome = getEnablementFor(endpointKey);
+ if (endpointSpecificOutcome != null) {
+ return endpointSpecificOutcome;
+ }
+
+ // All endpoints specific attributes have been looked at. Checking default value
+ // for the endpoint
+ if (!enabledByDefault) {
+ return new EndpointEnablement(false,
+ createDefaultEnablementMessage(endpointId, enabledByDefault,
+ endpointType));
+ }
+
+ if (endpointType != null) {
+ String globalTypeKey = createTechSpecificKey("all", endpointType);
+ EndpointEnablement globalTypeOutcome = getEnablementFor(globalTypeKey);
+ if (globalTypeOutcome != null) {
+ return globalTypeOutcome;
+ }
+ }
+ else {
+ // Check if there is a global tech required
+ EndpointEnablement anyTechGeneralOutcome = getAnyTechSpecificOutcomeFor("all");
+ if (anyTechGeneralOutcome != null) {
+ return anyTechGeneralOutcome;
+ }
+ }
+
+ String globalKey = createKey("all", "enabled");
+ EndpointEnablement globalOutCome = getEnablementFor(globalKey);
+ if (globalOutCome != null) {
+ return globalOutCome;
+ }
+ return new EndpointEnablement(enabledByDefault, createDefaultEnablementMessage(
+ endpointId, enabledByDefault, endpointType));
+ }
+
+ private String createDefaultEnablementMessage(String endpointId,
+ boolean enabledByDefault, EndpointType endpointType) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(String.format("endpoint '%s' ", endpointId));
+ if (endpointType != null) {
+ sb.append(String.format("(%s) ", endpointType.name().toLowerCase()));
+ }
+ sb.append(String.format("is %s by default",
+ (enabledByDefault ? "enabled" : "disabled")));
+ return sb.toString();
+ }
+
+ private EndpointEnablement getAnyTechSpecificOutcomeFor(String endpointId) {
+ for (EndpointType endpointType : EndpointType.values()) {
+ String key = createTechSpecificKey(endpointId, endpointType);
+ EndpointEnablement outcome = getEnablementFor(key);
+ if (outcome != null && outcome.isEnabled()) {
+ return outcome;
+ }
+ }
+ return null;
+ }
+
+ private String createTechSpecificKey(String endpointId, EndpointType endpointType) {
+ return createKey(endpointId, endpointType.name().toLowerCase() + ".enabled");
+ }
+
+ private String createKey(String endpointId, String suffix) {
+ return "endpoints." + endpointId + "." + suffix;
+ }
+
+ /**
+ * Return an {@link EndpointEnablement} for the specified key if it is set or
+ * {@code null} if the key is not present in the environment.
+ * @param key the key to check
+ * @return the outcome or {@code null} if the key is no set
+ */
+ private EndpointEnablement getEnablementFor(String key) {
+ if (this.environment.containsProperty(key)) {
+ boolean match = this.environment.getProperty(key, Boolean.class, true);
+ return new EndpointEnablement(match, String.format("found property %s", key));
+ }
+ return null;
+ }
+
+}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/condition/package-info.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/support/package-info.java
similarity index 81%
rename from spring-boot-actuator/src/main/java/org/springframework/boot/actuate/condition/package-info.java
rename to spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/support/package-info.java
index e6ec0c3589..0e7ec1a12f 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/condition/package-info.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/support/package-info.java
@@ -15,6 +15,6 @@
*/
/**
- * {@code @Condition} annotations and supporting classes.
+ * Support classes for the Actuator's endpoint auto-configuration.
*/
-package org.springframework.boot.actuate.condition;
+package org.springframework.boot.actuate.autoconfigure.endpoint.support;
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthMvcEndpointProperties.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/HealthWebEndpointExtensionProperties.java
similarity index 70%
rename from spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthMvcEndpointProperties.java
rename to spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/HealthWebEndpointExtensionProperties.java
index e0a367895d..c8275c4690 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthMvcEndpointProperties.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/HealthWebEndpointExtensionProperties.java
@@ -14,35 +14,35 @@
* limitations under the License.
*/
-package org.springframework.boot.actuate.autoconfigure.health;
+package org.springframework.boot.actuate.autoconfigure.endpoint.web;
import java.util.HashMap;
import java.util.Map;
-import org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint;
+import org.springframework.boot.actuate.endpoint.web.HealthWebEndpointExtension;
import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.http.HttpStatus;
/**
- * Configuration properties for the {@link HealthMvcEndpoint}.
+ * Configuration properties for the {@link HealthWebEndpointExtension}.
*
* @author Christian Dupuis
+ * @author Andy Wilkinson
* @since 2.0.0
*/
@ConfigurationProperties(prefix = "endpoints.health")
-public class HealthMvcEndpointProperties {
+public class HealthWebEndpointExtensionProperties {
/**
* Mapping of health statuses to HttpStatus codes. By default, registered health
* statuses map to sensible defaults (i.e. UP maps to 200).
*/
- private Map mapping = new HashMap<>();
+ private Map mapping = new HashMap<>();
- public Map getMapping() {
+ public Map getMapping() {
return this.mapping;
}
- public void setMapping(Map mapping) {
+ public void setMapping(Map mapping) {
this.mapping = mapping;
}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/WebEndpointManagementContextConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/WebEndpointManagementContextConfiguration.java
new file mode 100644
index 0000000000..9d0f929c82
--- /dev/null
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/WebEndpointManagementContextConfiguration.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2012-2017 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.boot.actuate.autoconfigure.endpoint.web;
+
+import org.springframework.boot.actuate.autoconfigure.ManagementContextConfiguration;
+import org.springframework.boot.actuate.autoconfigure.endpoint.ConditionalOnEnabledEndpoint;
+import org.springframework.boot.actuate.endpoint.AuditEventsEndpoint;
+import org.springframework.boot.actuate.endpoint.HealthEndpoint;
+import org.springframework.boot.actuate.endpoint.web.AuditEventsWebEndpointExtension;
+import org.springframework.boot.actuate.endpoint.web.HealthWebEndpointExtension;
+import org.springframework.boot.actuate.endpoint.web.HeapDumpWebEndpoint;
+import org.springframework.boot.actuate.endpoint.web.LogFileWebEndpoint;
+import org.springframework.boot.autoconfigure.condition.ConditionMessage;
+import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.SearchStrategy;
+import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ConditionContext;
+import org.springframework.context.annotation.Conditional;
+import org.springframework.core.env.Environment;
+import org.springframework.core.type.AnnotatedTypeMetadata;
+import org.springframework.util.StringUtils;
+
+/**
+ * Configuration for web-specific endpoint functionality.
+ *
+ * @author Andy Wilkinson
+ * @since 2.0.0
+ */
+@ManagementContextConfiguration
+@EnableConfigurationProperties(HealthWebEndpointExtensionProperties.class)
+public class WebEndpointManagementContextConfiguration {
+
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnEnabledEndpoint
+ public HeapDumpWebEndpoint heapDumpWebEndpoint() {
+ return new HeapDumpWebEndpoint();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnEnabledEndpoint
+ @ConditionalOnBean(value = HealthEndpoint.class, search = SearchStrategy.CURRENT)
+ public HealthWebEndpointExtension healthWebEndpointExtension(HealthEndpoint delegate,
+ HealthWebEndpointExtensionProperties extensionProperties) {
+ HealthWebEndpointExtension webExtension = new HealthWebEndpointExtension(
+ delegate);
+ if (extensionProperties.getMapping() != null) {
+ webExtension.addStatusMapping(extensionProperties.getMapping());
+ }
+ return webExtension;
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnEnabledEndpoint
+ @ConditionalOnBean(value = AuditEventsEndpoint.class, search = SearchStrategy.CURRENT)
+ public AuditEventsWebEndpointExtension auditEventsWebEndpointExtension(
+ AuditEventsEndpoint delegate) {
+ return new AuditEventsWebEndpointExtension(delegate);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ @Conditional(LogFileCondition.class)
+ public LogFileWebEndpoint logfileWebEndpoint(Environment environment) {
+ return new LogFileWebEndpoint(environment);
+ }
+
+ private static class LogFileCondition extends SpringBootCondition {
+
+ @Override
+ public ConditionOutcome getMatchOutcome(ConditionContext context,
+ AnnotatedTypeMetadata metadata) {
+ Environment environment = context.getEnvironment();
+ String config = environment.resolvePlaceholders("${logging.file:}");
+ ConditionMessage.Builder message = ConditionMessage.forCondition("Log File");
+ if (StringUtils.hasText(config)) {
+ return ConditionOutcome
+ .match(message.found("logging.file").items(config));
+ }
+ config = environment.resolvePlaceholders("${logging.path:}");
+ if (StringUtils.hasText(config)) {
+ return ConditionOutcome
+ .match(message.found("logging.path").items(config));
+ }
+ config = environment.getProperty("endpoints.logfile.external-file");
+ if (StringUtils.hasText(config)) {
+ return ConditionOutcome.match(
+ message.found("endpoints.logfile.external-file").items(config));
+ }
+ return ConditionOutcome.noMatch(message.didNotFind("logging file").atAll());
+ }
+
+ }
+
+}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/package-info.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/package-info.java
new file mode 100644
index 0000000000..9873d97fab
--- /dev/null
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2012-2015 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.
+ */
+
+/**
+ * {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
+ * Auto-configuration} for the Actuator's web endpoints.
+ */
+package org.springframework.boot.actuate.autoconfigure.endpoint.web;
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/security/ManagementWebSecurityAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/security/ManagementWebSecurityAutoConfiguration.java
index a3b593146b..c4e312b8eb 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/security/ManagementWebSecurityAutoConfiguration.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/security/ManagementWebSecurityAutoConfiguration.java
@@ -17,6 +17,7 @@
package org.springframework.boot.actuate.autoconfigure.security;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
@@ -28,9 +29,6 @@ import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.actuate.autoconfigure.endpoint.ManagementContextResolver;
import org.springframework.boot.actuate.autoconfigure.web.ManagementServerProperties;
-import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping;
-import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
-import org.springframework.boot.actuate.endpoint.mvc.NamedMvcEndpoint;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
@@ -51,6 +49,9 @@ import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.boot.autoconfigure.security.SpringBootWebSecurityConfiguration;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.boot.endpoint.EndpointInfo;
+import org.springframework.boot.endpoint.web.WebEndpointOperation;
+import org.springframework.boot.endpoint.web.mvc.WebEndpointServletHandlerMapping;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ConditionContext;
@@ -218,7 +219,8 @@ public class ManagementWebSecurityAutoConfiguration {
AuthenticationEntryPoint entryPoint = entryPoint();
http.exceptionHandling().authenticationEntryPoint(entryPoint);
// Match all the requests for actuator endpoints ...
- http.requestMatcher(matcher);
+ http.requestMatcher(matcher).authorizeRequests().anyRequest()
+ .authenticated();
http.httpBasic().authenticationEntryPoint(entryPoint).and().cors();
// No cookies for management endpoints by default
http.csrf().disable();
@@ -256,20 +258,21 @@ public class ManagementWebSecurityAutoConfiguration {
private static class EndpointPaths {
- public String[] getPaths(EndpointHandlerMapping endpointHandlerMapping) {
+ public String[] getPaths(
+ WebEndpointServletHandlerMapping endpointHandlerMapping) {
if (endpointHandlerMapping == null) {
return NO_PATHS;
}
- Set extends MvcEndpoint> endpoints = endpointHandlerMapping.getEndpoints();
+ Collection> endpoints = endpointHandlerMapping
+ .getEndpoints();
Set paths = new LinkedHashSet<>(endpoints.size());
- for (MvcEndpoint endpoint : endpoints) {
- String path = endpointHandlerMapping.getPath(endpoint.getPath());
+ for (EndpointInfo endpoint : endpoints) {
+ String path = endpointHandlerMapping.getEndpointPath() + "/"
+ + endpoint.getId();
paths.add(path);
- if (!path.equals("")) {
- paths.add(path + "/**");
- // Add Spring MVC-generated additional paths
- paths.add(path + ".*");
- }
+ paths.add(path + "/**");
+ // Add Spring MVC-generated additional paths
+ paths.add(path + ".*");
paths.add(path + "/");
}
return paths.toArray(new String[paths.size()]);
@@ -300,7 +303,7 @@ public class ManagementWebSecurityAutoConfiguration {
server.getServlet().getPath(path) + "/**");
return matcher;
}
- // Match everything, including the sensitive and non-sensitive paths
+ // Match all endpoint paths
return new LazyEndpointPathRequestMatcher(contextResolver,
new EndpointPaths());
}
@@ -323,7 +326,7 @@ public class ManagementWebSecurityAutoConfiguration {
ServerProperties server = this.contextResolver.getApplicationContext()
.getBean(ServerProperties.class);
List matchers = new ArrayList<>();
- EndpointHandlerMapping endpointHandlerMapping = getRequiredEndpointHandlerMapping();
+ WebEndpointServletHandlerMapping endpointHandlerMapping = getRequiredEndpointHandlerMapping();
for (String path : this.endpointPaths.getPaths(endpointHandlerMapping)) {
matchers.add(
new AntPathRequestMatcher(server.getServlet().getPath(path)));
@@ -331,16 +334,18 @@ public class ManagementWebSecurityAutoConfiguration {
return (matchers.isEmpty() ? MATCH_NONE : new OrRequestMatcher(matchers));
}
- private EndpointHandlerMapping getRequiredEndpointHandlerMapping() {
- EndpointHandlerMapping endpointHandlerMapping = null;
+ private WebEndpointServletHandlerMapping getRequiredEndpointHandlerMapping() {
+ WebEndpointServletHandlerMapping endpointHandlerMapping = null;
ApplicationContext context = this.contextResolver.getApplicationContext();
- if (context.getBeanNamesForType(EndpointHandlerMapping.class).length > 0) {
- endpointHandlerMapping = context.getBean(EndpointHandlerMapping.class);
+ if (context.getBeanNamesForType(
+ WebEndpointServletHandlerMapping.class).length > 0) {
+ endpointHandlerMapping = context
+ .getBean(WebEndpointServletHandlerMapping.class);
}
if (endpointHandlerMapping == null) {
// Maybe there are actually no endpoints (e.g. management.port=-1)
- endpointHandlerMapping = new EndpointHandlerMapping(
- Collections.emptySet());
+ endpointHandlerMapping = new WebEndpointServletHandlerMapping("",
+ Collections.emptySet());
}
return endpointHandlerMapping;
}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cloudfoundry/CloudFoundryDiscoveryMvcEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cloudfoundry/CloudFoundryDiscoveryMvcEndpoint.java
index a1ae48e7dd..f487938dda 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cloudfoundry/CloudFoundryDiscoveryMvcEndpoint.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cloudfoundry/CloudFoundryDiscoveryMvcEndpoint.java
@@ -16,75 +16,62 @@
package org.springframework.boot.actuate.cloudfoundry;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Set;
-
-import javax.servlet.http.HttpServletRequest;
-
-import org.springframework.boot.actuate.endpoint.mvc.AbstractMvcEndpoint;
-import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
-import org.springframework.boot.actuate.endpoint.mvc.NamedMvcEndpoint;
-import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.ResponseBody;
-
/**
* {@link MvcEndpoint} to expose HAL-formatted JSON for Cloud Foundry specific actuator
* endpoints.
*
* @author Madhura Bhave
*/
-class CloudFoundryDiscoveryMvcEndpoint extends AbstractMvcEndpoint {
+class CloudFoundryDiscoveryMvcEndpoint {
- private final Set endpoints;
+ // TODO Port to new infrastructure
- CloudFoundryDiscoveryMvcEndpoint(Set endpoints) {
- super("");
- this.endpoints = endpoints;
- }
-
- @RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE)
- @ResponseBody
- public Map> links(HttpServletRequest request) {
- Map links = new LinkedHashMap<>();
- String url = request.getRequestURL().toString();
- if (url.endsWith("/")) {
- url = url.substring(0, url.length() - 1);
- }
- links.put("self", Link.withHref(url));
- AccessLevel accessLevel = AccessLevel.get(request);
- for (NamedMvcEndpoint endpoint : this.endpoints) {
- if (accessLevel != null && accessLevel.isAccessAllowed(endpoint.getPath())) {
- links.put(endpoint.getName(),
- Link.withHref(url + "/" + endpoint.getName()));
- }
- }
- return Collections.singletonMap("_links", links);
- }
-
- /**
- * Details for a link in the HAL response.
- */
- static class Link {
-
- private String href;
-
- public String getHref() {
- return this.href;
- }
-
- public void setHref(String href) {
- this.href = href;
- }
-
- static Link withHref(Object href) {
- Link link = new Link();
- link.setHref(href.toString());
- return link;
- }
-
- }
+ // private final Set endpoints;
+ //
+ // CloudFoundryDiscoveryMvcEndpoint(Set endpoints) {
+ // this.endpoints = endpoints;
+ // }
+ //
+ // @RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE)
+ // @ResponseBody
+ // public Map> links(HttpServletRequest request) {
+ // Map links = new LinkedHashMap<>();
+ // String url = request.getRequestURL().toString();
+ // if (url.endsWith("/")) {
+ // url = url.substring(0, url.length() - 1);
+ // }
+ // links.put("self", Link.withHref(url));
+ // AccessLevel accessLevel = AccessLevel.get(request);
+ // for (NamedMvcEndpoint endpoint : this.endpoints) {
+ // if (accessLevel != null && accessLevel.isAccessAllowed(endpoint.getPath())) {
+ // links.put(endpoint.getName(),
+ // Link.withHref(url + "/" + endpoint.getName()));
+ // }
+ // }
+ // return Collections.singletonMap("_links", links);
+ // }
+ //
+ // /**
+ // * Details for a link in the HAL response.
+ // */
+ // static class Link {
+ //
+ // private String href;
+ //
+ // public String getHref() {
+ // return this.href;
+ // }
+ //
+ // public void setHref(String href) {
+ // this.href = href;
+ // }
+ //
+ // static Link withHref(Object href) {
+ // Link link = new Link();
+ // link.setHref(href.toString());
+ // return link;
+ // }
+ //
+ // }
}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cloudfoundry/CloudFoundryEndpointHandlerMapping.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cloudfoundry/CloudFoundryEndpointHandlerMapping.java
deleted file mode 100644
index 42faa7cdee..0000000000
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cloudfoundry/CloudFoundryEndpointHandlerMapping.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright 2012-2017 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.boot.actuate.cloudfoundry;
-
-import java.util.Iterator;
-import java.util.Set;
-
-import org.springframework.boot.actuate.endpoint.Endpoint;
-import org.springframework.boot.actuate.endpoint.mvc.AbstractEndpointHandlerMapping;
-import org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint;
-import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
-import org.springframework.boot.actuate.endpoint.mvc.NamedMvcEndpoint;
-import org.springframework.web.cors.CorsConfiguration;
-import org.springframework.web.servlet.HandlerInterceptor;
-import org.springframework.web.servlet.HandlerMapping;
-
-/**
- * {@link HandlerMapping} to map {@link Endpoint}s to Cloud Foundry specific URLs.
- *
- * @author Madhura Bhave
- * @since 2.0.0
- */
-public class CloudFoundryEndpointHandlerMapping
- extends AbstractEndpointHandlerMapping {
-
- public CloudFoundryEndpointHandlerMapping(Set extends NamedMvcEndpoint> endpoints,
- CorsConfiguration corsConfiguration, HandlerInterceptor securityInterceptor) {
- super(endpoints, corsConfiguration);
- setSecurityInterceptor(securityInterceptor);
- }
-
- @Override
- protected void postProcessEndpoints(Set endpoints) {
- super.postProcessEndpoints(endpoints);
- Iterator iterator = endpoints.iterator();
- HealthMvcEndpoint healthMvcEndpoint = null;
- while (iterator.hasNext()) {
- NamedMvcEndpoint endpoint = iterator.next();
- if (endpoint instanceof HealthMvcEndpoint) {
- iterator.remove();
- healthMvcEndpoint = (HealthMvcEndpoint) endpoint;
- }
- }
- if (healthMvcEndpoint != null) {
- endpoints.add(
- new CloudFoundryHealthMvcEndpoint(healthMvcEndpoint.getDelegate()));
- }
- }
-
- @Override
- public void afterPropertiesSet() {
- super.afterPropertiesSet();
- detectHandlerMethods(new CloudFoundryDiscoveryMvcEndpoint(getEndpoints()));
- }
-
- @Override
- protected String getPath(MvcEndpoint endpoint) {
- if (endpoint instanceof NamedMvcEndpoint) {
- return "/" + ((NamedMvcEndpoint) endpoint).getName();
- }
- return super.getPath(endpoint);
- }
-
-}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cloudfoundry/CloudFoundryHealthMvcEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cloudfoundry/CloudFoundryHealthMvcEndpoint.java
index 49c4e10974..1b5e202f4d 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cloudfoundry/CloudFoundryHealthMvcEndpoint.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cloudfoundry/CloudFoundryHealthMvcEndpoint.java
@@ -16,31 +16,29 @@
package org.springframework.boot.actuate.cloudfoundry;
-import java.security.Principal;
-
-import javax.servlet.http.HttpServletRequest;
-
import org.springframework.boot.actuate.endpoint.HealthEndpoint;
-import org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint;
+import org.springframework.boot.actuate.endpoint.web.HealthWebEndpointExtension;
/**
- * Extension of {@link HealthMvcEndpoint} for Cloud Foundry. Since security for Cloud
- * Foundry actuators is already handled by the {@link CloudFoundrySecurityInterceptor},
- * this endpoint skips the additional security checks done by the regular
- * {@link HealthMvcEndpoint}.
+ * Extension of {@link HealthWebEndpointExtension} for Cloud Foundry. Since security for
+ * Cloud Foundry actuators is already handled by the
+ * {@link CloudFoundrySecurityInterceptor}, this endpoint skips the additional security
+ * checks done by the regular {@link HealthWebEndpointExtension}.
*
* @author Madhura Bhave
*/
-class CloudFoundryHealthMvcEndpoint extends HealthMvcEndpoint {
+class CloudFoundryHealthMvcEndpoint extends HealthWebEndpointExtension {
+
+ // TODO Port to new infrastructure
CloudFoundryHealthMvcEndpoint(HealthEndpoint delegate) {
super(delegate);
}
-
- @Override
- protected boolean exposeHealthDetails(HttpServletRequest request,
- Principal principal) {
- return true;
- }
+ //
+ // @Override
+ // protected boolean exposeHealthDetails(HttpServletRequest request,
+ // Principal principal) {
+ // return true;
+ // }
}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cloudfoundry/CloudFoundrySecurityInterceptor.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cloudfoundry/CloudFoundrySecurityInterceptor.java
index 9e12a28861..3a766085a7 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cloudfoundry/CloudFoundrySecurityInterceptor.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cloudfoundry/CloudFoundrySecurityInterceptor.java
@@ -23,12 +23,6 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.boot.actuate.cloudfoundry.CloudFoundryAuthorizationException.Reason;
-import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
-import org.springframework.http.HttpMethod;
-import org.springframework.http.MediaType;
-import org.springframework.util.StringUtils;
-import org.springframework.web.cors.CorsUtils;
-import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
@@ -57,52 +51,54 @@ public class CloudFoundrySecurityInterceptor extends HandlerInterceptorAdapter {
this.applicationId = applicationId;
}
+ // TODO Port to new infrastructure
+
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
- if (CorsUtils.isPreFlightRequest(request)) {
- return true;
- }
- try {
- if (!StringUtils.hasText(this.applicationId)) {
- throw new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE,
- "Application id is not available");
- }
- if (this.cloudFoundrySecurityService == null) {
- throw new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE,
- "Cloud controller URL is not available");
- }
- HandlerMethod handlerMethod = (HandlerMethod) handler;
- if (HttpMethod.OPTIONS.matches(request.getMethod())
- && !(handlerMethod.getBean() instanceof MvcEndpoint)) {
- return true;
- }
- MvcEndpoint mvcEndpoint = (MvcEndpoint) handlerMethod.getBean();
- check(request, mvcEndpoint);
- }
- catch (CloudFoundryAuthorizationException ex) {
- logger.error(ex);
- response.setContentType(MediaType.APPLICATION_JSON.toString());
- response.getWriter()
- .write("{\"security_error\":\"" + ex.getMessage() + "\"}");
- response.setStatus(ex.getStatusCode().value());
- return false;
- }
+ // if (CorsUtils.isPreFlightRequest(request)) {
+ // return true;
+ // }
+ // try {
+ // if (!StringUtils.hasText(this.applicationId)) {
+ // throw new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE,
+ // "Application id is not available");
+ // }
+ // if (this.cloudFoundrySecurityService == null) {
+ // throw new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE,
+ // "Cloud controller URL is not available");
+ // }
+ // HandlerMethod handlerMethod = (HandlerMethod) handler;
+ // if (HttpMethod.OPTIONS.matches(request.getMethod())
+ // && !(handlerMethod.getBean() instanceof MvcEndpoint)) {
+ // return true;
+ // }
+ // MvcEndpoint mvcEndpoint = (MvcEndpoint) handlerMethod.getBean();
+ // check(request, mvcEndpoint);
+ // }
+ // catch (CloudFoundryAuthorizationException ex) {
+ // logger.error(ex);
+ // response.setContentType(MediaType.APPLICATION_JSON.toString());
+ // response.getWriter()
+ // .write("{\"security_error\":\"" + ex.getMessage() + "\"}");
+ // response.setStatus(ex.getStatusCode().value());
+ // return false;
+ // }
return true;
}
- private void check(HttpServletRequest request, MvcEndpoint mvcEndpoint)
- throws Exception {
- Token token = getToken(request);
- this.tokenValidator.validate(token);
- AccessLevel accessLevel = this.cloudFoundrySecurityService
- .getAccessLevel(token.toString(), this.applicationId);
- if (!accessLevel.isAccessAllowed(mvcEndpoint.getPath())) {
- throw new CloudFoundryAuthorizationException(Reason.ACCESS_DENIED,
- "Access denied");
- }
- accessLevel.put(request);
- }
+ // private void check(HttpServletRequest request, MvcEndpoint mvcEndpoint)
+ // throws Exception {
+ // Token token = getToken(request);
+ // this.tokenValidator.validate(token);
+ // AccessLevel accessLevel = this.cloudFoundrySecurityService
+ // .getAccessLevel(token.toString(), this.applicationId);
+ // if (!accessLevel.isAccessAllowed(mvcEndpoint.getPath())) {
+ // throw new CloudFoundryAuthorizationException(Reason.ACCESS_DENIED,
+ // "Access denied");
+ // }
+ // accessLevel.put(request);
+ // }
private Token getToken(HttpServletRequest request) {
String authorization = request.getHeader("Authorization");
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/condition/ConditionalOnEnabledEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/condition/ConditionalOnEnabledEndpoint.java
deleted file mode 100644
index 1363e1fc8a..0000000000
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/condition/ConditionalOnEnabledEndpoint.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2012-2016 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.boot.actuate.condition;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-import org.springframework.context.annotation.Conditional;
-
-/**
- * {@link Conditional} that checks whether or not an endpoint is enabled. Matches if the
- * value of the {@code endpoints..enabled} property is {@code true}. Does not match
- * if the property's value or {@code enabledByDefault} is {@code false}. Otherwise,
- * matches if the value of the {@code endpoints.enabled} property is {@code true} or if
- * the property is not configured.
- *
- * @author Andy Wilkinson
- * @since 1.2.4
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ ElementType.METHOD, ElementType.TYPE })
-@Conditional(OnEnabledEndpointCondition.class)
-@Documented
-public @interface ConditionalOnEnabledEndpoint {
-
- /**
- * The name of the endpoint.
- * @return The name of the endpoint
- */
- String value();
-
- /**
- * Returns whether or not the endpoint is enabled by default.
- * @return {@code true} if the endpoint is enabled by default, otherwise {@code false}
- */
- boolean enabledByDefault() default true;
-
-}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/condition/OnEnabledEndpointCondition.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/condition/OnEnabledEndpointCondition.java
deleted file mode 100644
index 6f0df8ea88..0000000000
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/condition/OnEnabledEndpointCondition.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright 2012-2017 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.boot.actuate.condition;
-
-import org.springframework.boot.autoconfigure.condition.ConditionMessage;
-import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
-import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
-import org.springframework.context.annotation.Condition;
-import org.springframework.context.annotation.ConditionContext;
-import org.springframework.core.annotation.AnnotationAttributes;
-import org.springframework.core.env.Environment;
-import org.springframework.core.type.AnnotatedTypeMetadata;
-
-/**
- * {@link Condition} that checks whether or not an endpoint is enabled.
- *
- * @author Andy Wilkinson
- * @author Madhura Bhave
- */
-class OnEnabledEndpointCondition extends SpringBootCondition {
-
- @Override
- public ConditionOutcome getMatchOutcome(ConditionContext context,
- AnnotatedTypeMetadata metadata) {
- AnnotationAttributes annotationAttributes = AnnotationAttributes.fromMap(metadata
- .getAnnotationAttributes(ConditionalOnEnabledEndpoint.class.getName()));
- String endpointName = annotationAttributes.getString("value");
- boolean enabledByDefault = annotationAttributes.getBoolean("enabledByDefault");
- ConditionOutcome outcome = determineEndpointOutcome(endpointName,
- enabledByDefault, context);
- if (outcome != null) {
- return outcome;
- }
- return determineAllEndpointsOutcome(context);
- }
-
- private ConditionOutcome determineEndpointOutcome(String endpointName,
- boolean enabledByDefault, ConditionContext context) {
- Environment environment = context.getEnvironment();
- String enabledProperty = "endpoints." + endpointName + ".enabled";
- if (environment.containsProperty(enabledProperty) || !enabledByDefault) {
- boolean match = environment.getProperty(enabledProperty, Boolean.class,
- enabledByDefault);
- ConditionMessage message = ConditionMessage
- .forCondition(ConditionalOnEnabledEndpoint.class,
- "(" + endpointName + ")")
- .because(match ? "enabled" : "disabled");
- return new ConditionOutcome(match, message);
- }
- return null;
- }
-
- private ConditionOutcome determineAllEndpointsOutcome(ConditionContext context) {
- boolean match = Boolean.valueOf(
- context.getEnvironment().getProperty("endpoints.enabled", "true"));
- ConditionMessage message = ConditionMessage
- .forCondition(ConditionalOnEnabledEndpoint.class)
- .because("All endpoints are " + (match ? "enabled" : "disabled")
- + " by default");
- return new ConditionOutcome(match, message);
- }
-
-}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AbstractEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AbstractEndpoint.java
deleted file mode 100644
index b3debdedf6..0000000000
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AbstractEndpoint.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright 2012-2017 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.boot.actuate.endpoint;
-
-import java.util.regex.Pattern;
-
-import org.springframework.context.EnvironmentAware;
-import org.springframework.core.env.Environment;
-import org.springframework.util.Assert;
-
-/**
- * Abstract base for {@link Endpoint} implementations.
- *
- * @param the endpoint data type
- * @author Phillip Webb
- * @author Christian Dupuis
- */
-public abstract class AbstractEndpoint implements Endpoint, EnvironmentAware {
-
- private static final Pattern ID_PATTERN = Pattern.compile("\\w+");
-
- private Environment environment;
-
- /**
- * Endpoint identifier. With HTTP monitoring the identifier of the endpoint is mapped
- * to a URL (e.g. 'foo' is mapped to '/foo').
- */
- private String id;
-
- /**
- * Enable the endpoint.
- */
- private Boolean enabled;
-
- /**
- * Create a new endpoint instance. The endpoint will enabled flag will be based on the
- * spring {@link Environment} unless explicitly set.
- * @param id the endpoint ID
- */
- public AbstractEndpoint(String id) {
- setId(id);
- }
-
- /**
- * Create a new endpoint instance.
- * @param id the endpoint ID
- * @param enabled if the endpoint is enabled or not.
- */
- public AbstractEndpoint(String id, boolean enabled) {
- setId(id);
- this.enabled = enabled;
- }
-
- protected final Environment getEnvironment() {
- return this.environment;
- }
-
- @Override
- public void setEnvironment(Environment environment) {
- this.environment = environment;
- }
-
- @Override
- public String getId() {
- return this.id;
- }
-
- public void setId(String id) {
- Assert.notNull(id, "Id must not be null");
- Assert.isTrue(ID_PATTERN.matcher(id).matches(),
- "Id must only contains letters, numbers and '_'");
- this.id = id;
- }
-
- @Override
- public boolean isEnabled() {
- return EndpointProperties.isEnabled(this.environment, this.enabled);
- }
-
- public void setEnabled(Boolean enabled) {
- this.enabled = enabled;
- }
-
-}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AuditEventsEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AuditEventsEndpoint.java
new file mode 100644
index 0000000000..9468dad189
--- /dev/null
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AuditEventsEndpoint.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2012-2017 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.boot.actuate.endpoint;
+
+import java.util.Date;
+import java.util.List;
+
+import org.springframework.boot.actuate.audit.AuditEvent;
+import org.springframework.boot.actuate.audit.AuditEventRepository;
+import org.springframework.boot.endpoint.Endpoint;
+import org.springframework.boot.endpoint.ReadOperation;
+import org.springframework.util.Assert;
+
+/**
+ * {@link Endpoint} to expose audit events.
+ *
+ * @author Andy Wilkinson
+ * @since 2.0.0
+ */
+@Endpoint(id = "auditevents")
+public class AuditEventsEndpoint {
+
+ private final AuditEventRepository auditEventRepository;
+
+ public AuditEventsEndpoint(AuditEventRepository auditEventRepository) {
+ Assert.notNull(auditEventRepository, "AuditEventRepository must not be null");
+ this.auditEventRepository = auditEventRepository;
+ }
+
+ @ReadOperation
+ public List eventsWithPrincipalDateAfterAndType(String principal,
+ Date after, String type) {
+ return this.auditEventRepository.find(principal, after, type);
+ }
+
+}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AutoConfigurationReportEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AutoConfigurationReportEndpoint.java
index 313a23d605..b80f99ec81 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AutoConfigurationReportEndpoint.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AutoConfigurationReportEndpoint.java
@@ -26,13 +26,12 @@ import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.actuate.endpoint.AutoConfigurationReportEndpoint.Report;
import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;
import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport.ConditionAndOutcome;
import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport.ConditionAndOutcomes;
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
-import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.endpoint.Endpoint;
+import org.springframework.boot.endpoint.ReadOperation;
import org.springframework.context.annotation.Condition;
import org.springframework.util.ClassUtils;
import org.springframework.util.LinkedMultiValueMap;
@@ -47,19 +46,19 @@ import org.springframework.util.StringUtils;
* @author Dave Syer
* @author Andy Wilkinson
*/
-@ConfigurationProperties(prefix = "endpoints.autoconfig")
-public class AutoConfigurationReportEndpoint extends AbstractEndpoint {
+@Endpoint(id = "autoconfig")
+public class AutoConfigurationReportEndpoint {
- @Autowired
- private ConditionEvaluationReport autoConfigurationReport;
+ private final ConditionEvaluationReport conditionEvaluationReport;
- public AutoConfigurationReportEndpoint() {
- super("autoconfig");
+ public AutoConfigurationReportEndpoint(
+ ConditionEvaluationReport conditionEvaluationReport) {
+ this.conditionEvaluationReport = conditionEvaluationReport;
}
- @Override
- public Report invoke() {
- return new Report(this.autoConfigurationReport);
+ @ReadOperation
+ public Report getEvaluationReport() {
+ return new Report(this.conditionEvaluationReport);
}
/**
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/BeansEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/BeansEndpoint.java
index e646f4580d..54b7e79939 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/BeansEndpoint.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/BeansEndpoint.java
@@ -21,7 +21,8 @@ import java.util.List;
import java.util.Set;
import org.springframework.beans.BeansException;
-import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.endpoint.Endpoint;
+import org.springframework.boot.endpoint.ReadOperation;
import org.springframework.boot.json.JsonParser;
import org.springframework.boot.json.JsonParserFactory;
import org.springframework.context.ApplicationContext;
@@ -40,18 +41,13 @@ import org.springframework.util.Assert;
* @author Dave Syer
* @author Andy Wilkinson
*/
-@ConfigurationProperties(prefix = "endpoints.beans")
-public class BeansEndpoint extends AbstractEndpoint>
- implements ApplicationContextAware {
+@Endpoint(id = "beans")
+public class BeansEndpoint implements ApplicationContextAware {
private final HierarchyAwareLiveBeansView liveBeansView = new HierarchyAwareLiveBeansView();
private final JsonParser parser = JsonParserFactory.getJsonParser();
- public BeansEndpoint() {
- super("beans");
- }
-
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
if (context.getEnvironment()
@@ -60,8 +56,8 @@ public class BeansEndpoint extends AbstractEndpoint>
}
}
- @Override
- public List invoke() {
+ @ReadOperation
+ public List beans() {
return this.parser.parseList(this.liveBeansView.getSnapshotAsJson());
}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpoint.java
index 8934b42a8b..fa8d5264b2 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpoint.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpoint.java
@@ -42,6 +42,8 @@ import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import org.springframework.beans.BeansException;
import org.springframework.boot.context.properties.ConfigurationBeanFactoryMetaData;
import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.endpoint.Endpoint;
+import org.springframework.boot.endpoint.ReadOperation;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.ClassUtils;
@@ -61,9 +63,9 @@ import org.springframework.util.StringUtils;
* @author Dave Syer
* @author Stephane Nicoll
*/
-@ConfigurationProperties(prefix = "endpoints.configprops")
-public class ConfigurationPropertiesReportEndpoint
- extends AbstractEndpoint> implements ApplicationContextAware {
+@Endpoint(id = "configprops")
+@ConfigurationProperties("endpoints.configprops")
+public class ConfigurationPropertiesReportEndpoint implements ApplicationContextAware {
private static final String CGLIB_FILTER_ID = "cglibFilter";
@@ -71,10 +73,6 @@ public class ConfigurationPropertiesReportEndpoint
private ApplicationContext context;
- public ConfigurationPropertiesReportEndpoint() {
- super("configprops");
- }
-
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
this.context = context;
@@ -84,8 +82,8 @@ public class ConfigurationPropertiesReportEndpoint
this.sanitizer.setKeysToSanitize(keysToSanitize);
}
- @Override
- public Map invoke() {
+ @ReadOperation
+ public Map configurationProperties() {
return extract(this.context);
}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/Endpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/Endpoint.java
deleted file mode 100644
index 3c2647ba3f..0000000000
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/Endpoint.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2012-2015 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.boot.actuate.endpoint;
-
-/**
- * An endpoint that can be used to expose useful information to operations. Usually
- * exposed via Spring MVC but could also be exposed using some other technique. Consider
- * extending {@link AbstractEndpoint} if you are developing your own endpoint.
- *
- * @param the endpoint data type
- * @author Phillip Webb
- * @author Dave Syer
- * @author Christian Dupuis
- * @see AbstractEndpoint
- */
-public interface Endpoint {
-
- /**
- * The logical ID of the endpoint. Must only contain simple letters, numbers and '_'
- * characters (i.e. a {@literal "\w"} regex).
- * @return the endpoint ID
- */
- String getId();
-
- /**
- * Return if the endpoint is enabled.
- * @return if the endpoint is enabled
- */
- boolean isEnabled();
-
- /**
- * Called to invoke the endpoint.
- * @return the results of the invocation
- */
- T invoke();
-
-}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/EnvironmentEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/EnvironmentEndpoint.java
index ab77de36f1..960a2ba183 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/EnvironmentEndpoint.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/EnvironmentEndpoint.java
@@ -21,11 +21,15 @@ import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.function.Predicate;
+import java.util.regex.Pattern;
+import java.util.stream.Stream;
-import org.springframework.boot.actuate.endpoint.EnvironmentEndpoint.EnvironmentDescriptor;
import org.springframework.boot.actuate.endpoint.EnvironmentEndpoint.EnvironmentDescriptor.PropertySourceDescriptor;
import org.springframework.boot.actuate.endpoint.EnvironmentEndpoint.EnvironmentDescriptor.PropertySourceDescriptor.PropertyValueDescriptor;
-import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.endpoint.Endpoint;
+import org.springframework.boot.endpoint.ReadOperation;
+import org.springframework.boot.endpoint.Selector;
import org.springframework.boot.origin.OriginLookup;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.ConfigurableEnvironment;
@@ -37,6 +41,9 @@ import org.springframework.core.env.PropertySource;
import org.springframework.core.env.PropertySources;
import org.springframework.core.env.PropertySourcesPropertyResolver;
import org.springframework.core.env.StandardEnvironment;
+import org.springframework.http.HttpStatus;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.ResponseStatus;
/**
* {@link Endpoint} to expose {@link ConfigurableEnvironment environment} information.
@@ -46,42 +53,54 @@ import org.springframework.core.env.StandardEnvironment;
* @author Christian Dupuis
* @author Madhura Bhave
*/
-@ConfigurationProperties(prefix = "endpoints.env")
-public class EnvironmentEndpoint extends AbstractEndpoint {
+@Endpoint(id = "env")
+public class EnvironmentEndpoint {
private final Sanitizer sanitizer = new Sanitizer();
- /**
- * Create a new {@link EnvironmentEndpoint} instance.
- */
- public EnvironmentEndpoint() {
- super("env");
+ private final Environment environment;
+
+ public EnvironmentEndpoint(Environment environment) {
+ this.environment = environment;
}
public void setKeysToSanitize(String... keysToSanitize) {
this.sanitizer.setKeysToSanitize(keysToSanitize);
}
- @Override
- public EnvironmentDescriptor invoke() {
+ @ReadOperation
+ public EnvironmentDescriptor environment(String pattern) {
+ if (StringUtils.hasText(pattern)) {
+ return environment(Pattern.compile(pattern).asPredicate());
+ }
+ return environment((name) -> true);
+ }
+
+ @ReadOperation
+ public Object getEnvironmentEntry(@Selector String toMatch) {
+ return environment((name) -> toMatch.equals(name));
+ }
+
+ private EnvironmentDescriptor environment(Predicate propertyNamePredicate) {
PropertyResolver resolver = getResolver();
List propertySources = new ArrayList<>();
getPropertySourcesAsMap().forEach((sourceName, source) -> {
if (source instanceof EnumerablePropertySource) {
- propertySources.add(describeSource(sourceName,
- (EnumerablePropertySource>) source, resolver));
+ propertySources.add(
+ describeSource(sourceName, (EnumerablePropertySource>) source,
+ resolver, propertyNamePredicate));
}
});
return new EnvironmentDescriptor(
- Arrays.asList(getEnvironment().getActiveProfiles()), propertySources);
+ Arrays.asList(this.environment.getActiveProfiles()), propertySources);
}
private PropertySourceDescriptor describeSource(String sourceName,
- EnumerablePropertySource> source, PropertyResolver resolver) {
+ EnumerablePropertySource> source, PropertyResolver resolver,
+ Predicate namePredicate) {
Map properties = new LinkedHashMap<>();
- for (String name : source.getPropertyNames()) {
- properties.put(name, describeValueOf(name, source, resolver));
- }
+ Stream.of(source.getPropertyNames()).filter(namePredicate).forEach(
+ (name) -> properties.put(name, describeValueOf(name, source, resolver)));
return new PropertySourceDescriptor(sourceName, properties);
}
@@ -94,7 +113,7 @@ public class EnvironmentEndpoint extends AbstractEndpoint
return new PropertyValueDescriptor(sanitize(name, resolved), origin);
}
- public PropertyResolver getResolver() {
+ private PropertyResolver getResolver() {
PlaceholderSanitizingPropertyResolver resolver = new PlaceholderSanitizingPropertyResolver(
getPropertySources(), this.sanitizer);
resolver.setIgnoreUnresolvableNestedPlaceholders(true);
@@ -111,9 +130,8 @@ public class EnvironmentEndpoint extends AbstractEndpoint
private MutablePropertySources getPropertySources() {
MutablePropertySources sources;
- Environment environment = getEnvironment();
- if (environment != null && environment instanceof ConfigurableEnvironment) {
- sources = ((ConfigurableEnvironment) environment).getPropertySources();
+ if (this.environment instanceof ConfigurableEnvironment) {
+ sources = ((ConfigurableEnvironment) this.environment).getPropertySources();
}
else {
sources = new StandardEnvironment().getPropertySources();
@@ -239,4 +257,17 @@ public class EnvironmentEndpoint extends AbstractEndpoint
}
}
+ /**
+ * Exception thrown when the specified property cannot be found.
+ */
+ @SuppressWarnings("serial")
+ @ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "No such property")
+ public static class NoSuchPropertyException extends RuntimeException {
+
+ public NoSuchPropertyException(String string) {
+ super(string);
+ }
+
+ }
+
}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/FlywayEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/FlywayEndpoint.java
index 4280ad2497..dc1d839931 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/FlywayEndpoint.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/FlywayEndpoint.java
@@ -28,8 +28,8 @@ import org.flywaydb.core.api.MigrationInfo;
import org.flywaydb.core.api.MigrationState;
import org.flywaydb.core.api.MigrationType;
-import org.springframework.boot.actuate.endpoint.FlywayEndpoint.FlywayReport;
-import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.endpoint.Endpoint;
+import org.springframework.boot.endpoint.ReadOperation;
import org.springframework.util.Assert;
/**
@@ -40,19 +40,18 @@ import org.springframework.util.Assert;
* @author Andy Wilkinson
* @since 1.3.0
*/
-@ConfigurationProperties(prefix = "endpoints.flyway")
-public class FlywayEndpoint extends AbstractEndpoint> {
+@Endpoint(id = "flyway")
+public class FlywayEndpoint {
private final Map flyways;
public FlywayEndpoint(Map flyways) {
- super("flyway");
Assert.notEmpty(flyways, "Flyways must be specified");
this.flyways = flyways;
}
- @Override
- public Map invoke() {
+ @ReadOperation
+ public Map flywayReports() {
Map reports = new HashMap<>();
for (Map.Entry entry : this.flyways.entrySet()) {
reports.put(entry.getKey(),
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/HealthEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/HealthEndpoint.java
index 3a62ed7801..a352d57b60 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/HealthEndpoint.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/HealthEndpoint.java
@@ -22,7 +22,8 @@ import org.springframework.boot.actuate.health.CompositeHealthIndicator;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthAggregator;
import org.springframework.boot.actuate.health.HealthIndicator;
-import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.endpoint.Endpoint;
+import org.springframework.boot.endpoint.ReadOperation;
import org.springframework.util.Assert;
/**
@@ -32,16 +33,11 @@ import org.springframework.util.Assert;
* @author Christian Dupuis
* @author Andy Wilkinson
*/
-@ConfigurationProperties(prefix = "endpoints.health")
-public class HealthEndpoint extends AbstractEndpoint {
+@Endpoint(id = "health")
+public class HealthEndpoint {
private final HealthIndicator healthIndicator;
- /**
- * Time to live for cached result, in milliseconds.
- */
- private long timeToLive = 1000;
-
/**
* Create a new {@link HealthEndpoint} instance.
* @param healthAggregator the health aggregator
@@ -49,7 +45,6 @@ public class HealthEndpoint extends AbstractEndpoint {
*/
public HealthEndpoint(HealthAggregator healthAggregator,
Map healthIndicators) {
- super("health");
Assert.notNull(healthAggregator, "HealthAggregator must not be null");
Assert.notNull(healthIndicators, "HealthIndicators must not be null");
CompositeHealthIndicator healthIndicator = new CompositeHealthIndicator(
@@ -60,28 +55,8 @@ public class HealthEndpoint extends AbstractEndpoint {
this.healthIndicator = healthIndicator;
}
- /**
- * Time to live for cached result. This is particularly useful to cache the result of
- * this endpoint to prevent a DOS attack if it is accessed anonymously.
- * @return time to live in milliseconds (default 1000)
- */
- public long getTimeToLive() {
- return this.timeToLive;
- }
-
- /**
- * Set the time to live for cached results.
- * @param timeToLive the time to live in milliseconds
- */
- public void setTimeToLive(long timeToLive) {
- this.timeToLive = timeToLive;
- }
-
- /**
- * Invoke all {@link HealthIndicator} delegates and collect their health information.
- */
- @Override
- public Health invoke() {
+ @ReadOperation
+ public Health health() {
return this.healthIndicator.health();
}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/InfoEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/InfoEndpoint.java
index 40cef3f38b..16d779a49a 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/InfoEndpoint.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/InfoEndpoint.java
@@ -21,7 +21,8 @@ import java.util.Map;
import org.springframework.boot.actuate.info.Info;
import org.springframework.boot.actuate.info.InfoContributor;
-import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.endpoint.Endpoint;
+import org.springframework.boot.endpoint.ReadOperation;
import org.springframework.util.Assert;
/**
@@ -31,8 +32,8 @@ import org.springframework.util.Assert;
* @author Meang Akira Tanaka
* @author Stephane Nicoll
*/
-@ConfigurationProperties(prefix = "endpoints.info")
-public class InfoEndpoint extends AbstractEndpoint> {
+@Endpoint(id = "info")
+public class InfoEndpoint {
private final List infoContributors;
@@ -41,13 +42,12 @@ public class InfoEndpoint extends AbstractEndpoint> {
* @param infoContributors the info contributors to use
*/
public InfoEndpoint(List infoContributors) {
- super("info");
Assert.notNull(infoContributors, "Info contributors must not be null");
this.infoContributors = infoContributors;
}
- @Override
- public Map invoke() {
+ @ReadOperation
+ public Map info() {
Info.Builder builder = new Info.Builder();
for (InfoContributor contributor : this.infoContributors) {
contributor.contribute(builder);
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/LiquibaseEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/LiquibaseEndpoint.java
index c36d989ca6..520b799d5c 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/LiquibaseEndpoint.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/LiquibaseEndpoint.java
@@ -16,7 +16,6 @@
package org.springframework.boot.actuate.endpoint;
-import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
@@ -35,8 +34,8 @@ import liquibase.database.DatabaseFactory;
import liquibase.database.jvm.JdbcConnection;
import liquibase.integration.spring.SpringLiquibase;
-import org.springframework.boot.actuate.endpoint.LiquibaseEndpoint.LiquibaseReport;
-import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.endpoint.Endpoint;
+import org.springframework.boot.endpoint.ReadOperation;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -46,23 +45,18 @@ import org.springframework.util.StringUtils;
* @author EddĂș MelĂ©ndez
* @since 1.3.0
*/
-@ConfigurationProperties(prefix = "endpoints.liquibase")
-public class LiquibaseEndpoint extends AbstractEndpoint> {
+@Endpoint(id = "liquibase")
+public class LiquibaseEndpoint {
private final Map liquibases;
- public LiquibaseEndpoint(SpringLiquibase liquibase) {
- this(Collections.singletonMap("default", liquibase));
- }
-
public LiquibaseEndpoint(Map liquibases) {
- super("liquibase");
Assert.notEmpty(liquibases, "Liquibases must be specified");
this.liquibases = liquibases;
}
- @Override
- public Map invoke() {
+ @ReadOperation
+ public Map liquibaseReports() {
Map reports = new HashMap<>();
DatabaseFactory factory = DatabaseFactory.getInstance();
StandardChangeLogHistoryService service = new StandardChangeLogHistoryService();
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/LoggersEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/LoggersEndpoint.java
index 7fe2270fef..3d2af7fc70 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/LoggersEndpoint.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/LoggersEndpoint.java
@@ -24,7 +24,10 @@ import java.util.NavigableSet;
import java.util.Set;
import java.util.TreeSet;
-import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.endpoint.Endpoint;
+import org.springframework.boot.endpoint.ReadOperation;
+import org.springframework.boot.endpoint.Selector;
+import org.springframework.boot.endpoint.WriteOperation;
import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.logging.LoggerConfiguration;
import org.springframework.boot.logging.LoggingSystem;
@@ -37,8 +40,8 @@ import org.springframework.util.Assert;
* @author Phillip Webb
* @since 1.5.0
*/
-@ConfigurationProperties(prefix = "endpoints.loggers")
-public class LoggersEndpoint extends AbstractEndpoint> {
+@Endpoint(id = "loggers")
+public class LoggersEndpoint {
private final LoggingSystem loggingSystem;
@@ -47,13 +50,12 @@ public class LoggersEndpoint extends AbstractEndpoint> {
* @param loggingSystem the logging system to expose
*/
public LoggersEndpoint(LoggingSystem loggingSystem) {
- super("loggers");
Assert.notNull(loggingSystem, "LoggingSystem must not be null");
this.loggingSystem = loggingSystem;
}
- @Override
- public Map invoke() {
+ @ReadOperation
+ public Map loggers() {
Collection configurations = this.loggingSystem
.getLoggerConfigurations();
if (configurations == null) {
@@ -65,6 +67,20 @@ public class LoggersEndpoint extends AbstractEndpoint> {
return result;
}
+ @ReadOperation
+ public LoggerLevels loggerLevels(@Selector String name) {
+ Assert.notNull(name, "Name must not be null");
+ LoggerConfiguration configuration = this.loggingSystem
+ .getLoggerConfiguration(name);
+ return (configuration == null ? null : new LoggerLevels(configuration));
+ }
+
+ @WriteOperation
+ public void configureLogLevel(@Selector String name, LogLevel configuredLevel) {
+ Assert.notNull(name, "Name must not be empty");
+ this.loggingSystem.setLogLevel(name, configuredLevel);
+ }
+
private NavigableSet getLevels() {
Set levels = this.loggingSystem.getSupportedLogLevels();
return new TreeSet<>(levels).descendingSet();
@@ -79,18 +95,6 @@ public class LoggersEndpoint extends AbstractEndpoint> {
return loggers;
}
- public LoggerLevels invoke(String name) {
- Assert.notNull(name, "Name must not be null");
- LoggerConfiguration configuration = this.loggingSystem
- .getLoggerConfiguration(name);
- return (configuration == null ? null : new LoggerLevels(configuration));
- }
-
- public void setLogLevel(String name, LogLevel level) {
- Assert.notNull(name, "Name must not be empty");
- this.loggingSystem.setLogLevel(name, level);
- }
-
/**
* Levels configured for a given logger exposed in a JSON friendly way.
*/
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/MetricsEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/MetricsEndpoint.java
index 612cdefa8a..0631679715 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/MetricsEndpoint.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/MetricsEndpoint.java
@@ -22,19 +22,24 @@ import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.function.Predicate;
+import java.util.regex.Pattern;
import org.springframework.boot.actuate.metrics.Metric;
-import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.endpoint.Endpoint;
+import org.springframework.boot.endpoint.ReadOperation;
+import org.springframework.boot.endpoint.Selector;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.util.Assert;
+import org.springframework.util.StringUtils;
/**
* {@link Endpoint} to expose a collection of {@link PublicMetrics}.
*
* @author Dave Syer
*/
-@ConfigurationProperties(prefix = "endpoints.metrics")
-public class MetricsEndpoint extends AbstractEndpoint> {
+@Endpoint(id = "metrics")
+public class MetricsEndpoint {
private final List publicMetrics;
@@ -52,7 +57,6 @@ public class MetricsEndpoint extends AbstractEndpoint> {
* {@link AnnotationAwareOrderComparator}.
*/
public MetricsEndpoint(Collection publicMetrics) {
- super("metrics");
Assert.notNull(publicMetrics, "PublicMetrics must not be null");
this.publicMetrics = new ArrayList<>(publicMetrics);
AnnotationAwareOrderComparator.sort(this.publicMetrics);
@@ -67,14 +71,31 @@ public class MetricsEndpoint extends AbstractEndpoint> {
this.publicMetrics.remove(metrics);
}
- @Override
- public Map invoke() {
+ @ReadOperation
+ public Map metrics(String pattern) {
+ return metrics(StringUtils.hasText(pattern)
+ ? Pattern.compile(pattern).asPredicate() : (name) -> true);
+ }
+
+ @ReadOperation
+ public Map metricNamed(@Selector String requiredName) {
+ Map metrics = metrics((name) -> name.equals(requiredName));
+ if (metrics.isEmpty()) {
+ return null;
+ }
+ return metrics;
+ }
+
+ private Map metrics(Predicate namePredicate) {
Map result = new LinkedHashMap<>();
List metrics = new ArrayList<>(this.publicMetrics);
for (PublicMetrics publicMetric : metrics) {
try {
for (Metric> metric : publicMetric.metrics()) {
- result.put(metric.getName(), metric.getValue());
+ if (namePredicate.test(metric.getName())
+ && metric.getValue() != null) {
+ result.put(metric.getName(), metric.getValue());
+ }
}
}
catch (Exception ex) {
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/MetricsEndpointMetricReader.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/MetricsEndpointMetricReader.java
index ee1eabbc2a..381956290f 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/MetricsEndpointMetricReader.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/MetricsEndpointMetricReader.java
@@ -44,7 +44,7 @@ public class MetricsEndpointMetricReader implements MetricReader {
@Override
public Metric> findOne(String metricName) {
Metric metric = null;
- Object value = this.endpoint.invoke().get(metricName);
+ Object value = this.endpoint.metrics(null).get(metricName);
if (value != null) {
metric = new Metric<>(metricName, (Number) value);
}
@@ -54,7 +54,7 @@ public class MetricsEndpointMetricReader implements MetricReader {
@Override
public Iterable> findAll() {
List> metrics = new ArrayList<>();
- Map values = this.endpoint.invoke();
+ Map values = this.endpoint.metrics(null);
Date timestamp = new Date();
for (Entry entry : values.entrySet()) {
String name = entry.getKey();
@@ -66,7 +66,7 @@ public class MetricsEndpointMetricReader implements MetricReader {
@Override
public long count() {
- return this.endpoint.invoke().size();
+ return this.endpoint.metrics(null).size();
}
}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/NamePatternFilter.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/NamePatternFilter.java
similarity index 97%
rename from spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/NamePatternFilter.java
rename to spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/NamePatternFilter.java
index db2ed158d0..141cf9c2b1 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/NamePatternFilter.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/NamePatternFilter.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.springframework.boot.actuate.endpoint.mvc;
+package org.springframework.boot.actuate.endpoint;
import java.util.HashMap;
import java.util.LinkedHashMap;
@@ -32,8 +32,7 @@ import java.util.regex.PatternSyntaxException;
* @author Phillip Webb
* @author Sergei Egorov
* @author Andy Wilkinson
- * @author Dylian Bego
- * @since 1.3.0
+ * @since 2.0.0
*/
abstract class NamePatternFilter {
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/RequestMappingEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/RequestMappingEndpoint.java
index c7caece589..ddc851522b 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/RequestMappingEndpoint.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/RequestMappingEndpoint.java
@@ -25,7 +25,8 @@ import java.util.Map.Entry;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
-import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.endpoint.Endpoint;
+import org.springframework.boot.endpoint.ReadOperation;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.web.method.HandlerMethod;
@@ -38,9 +39,8 @@ import org.springframework.web.servlet.handler.AbstractUrlHandlerMapping;
* @author Dave Syer
* @author Andy Wilkinson
*/
-@ConfigurationProperties(prefix = "endpoints.mappings")
-public class RequestMappingEndpoint extends AbstractEndpoint>
- implements ApplicationContextAware {
+@Endpoint(id = "mappings")
+public class RequestMappingEndpoint implements ApplicationContextAware {
private List handlerMappings = Collections.emptyList();
@@ -49,10 +49,6 @@ public class RequestMappingEndpoint extends AbstractEndpoint
private ApplicationContext applicationContext;
- public RequestMappingEndpoint() {
- super("mappings");
- }
-
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
@@ -75,8 +71,8 @@ public class RequestMappingEndpoint extends AbstractEndpoint
this.methodMappings = methodMappings;
}
- @Override
- public Map invoke() {
+ @ReadOperation
+ public Map mappings() {
Map result = new LinkedHashMap<>();
extractHandlerMappings(this.handlerMappings, result);
extractHandlerMappings(this.applicationContext, result);
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ShutdownEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ShutdownEndpoint.java
index 6c36ecc843..8026566337 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ShutdownEndpoint.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ShutdownEndpoint.java
@@ -20,7 +20,8 @@ import java.util.Collections;
import java.util.Map;
import org.springframework.beans.BeansException;
-import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.endpoint.Endpoint;
+import org.springframework.boot.endpoint.WriteOperation;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
@@ -32,9 +33,8 @@ import org.springframework.context.ConfigurableApplicationContext;
* @author Christian Dupuis
* @author Andy Wilkinson
*/
-@ConfigurationProperties(prefix = "endpoints.shutdown")
-public class ShutdownEndpoint extends AbstractEndpoint>
- implements ApplicationContextAware {
+@Endpoint(id = "shutdown", enabledByDefault = false)
+public class ShutdownEndpoint implements ApplicationContextAware {
private static final Map NO_CONTEXT_MESSAGE = Collections
.unmodifiableMap(Collections.singletonMap("message",
@@ -46,15 +46,8 @@ public class ShutdownEndpoint extends AbstractEndpoint>
private ConfigurableApplicationContext context;
- /**
- * Create a new {@link ShutdownEndpoint} instance.
- */
- public ShutdownEndpoint() {
- super("shutdown", false);
- }
-
- @Override
- public Map invoke() {
+ @WriteOperation
+ public Map shutdown() {
if (this.context == null) {
return NO_CONTEXT_MESSAGE;
}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/DumpEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ThreadDumpEndpoint.java
similarity index 73%
rename from spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/DumpEndpoint.java
rename to spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ThreadDumpEndpoint.java
index 423b4921e1..7e62399850 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/DumpEndpoint.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ThreadDumpEndpoint.java
@@ -21,25 +21,19 @@ import java.lang.management.ThreadInfo;
import java.util.Arrays;
import java.util.List;
-import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.endpoint.Endpoint;
+import org.springframework.boot.endpoint.ReadOperation;
/**
* {@link Endpoint} to expose thread info.
*
* @author Dave Syer
*/
-@ConfigurationProperties(prefix = "endpoints.dump")
-public class DumpEndpoint extends AbstractEndpoint> {
+@Endpoint(id = "threaddump")
+public class ThreadDumpEndpoint {
- /**
- * Create a new {@link DumpEndpoint} instance.
- */
- public DumpEndpoint() {
- super("dump");
- }
-
- @Override
- public List invoke() {
+ @ReadOperation
+ public List threadDump() {
return Arrays
.asList(ManagementFactory.getThreadMXBean().dumpAllThreads(true, true));
}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/TraceEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/TraceEndpoint.java
index eb30b9e64e..11f2291e1b 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/TraceEndpoint.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/TraceEndpoint.java
@@ -20,7 +20,8 @@ import java.util.List;
import org.springframework.boot.actuate.trace.Trace;
import org.springframework.boot.actuate.trace.TraceRepository;
-import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.endpoint.Endpoint;
+import org.springframework.boot.endpoint.ReadOperation;
import org.springframework.util.Assert;
/**
@@ -28,8 +29,8 @@ import org.springframework.util.Assert;
*
* @author Dave Syer
*/
-@ConfigurationProperties(prefix = "endpoints.trace")
-public class TraceEndpoint extends AbstractEndpoint> {
+@Endpoint(id = "trace")
+public class TraceEndpoint {
private final TraceRepository repository;
@@ -38,13 +39,12 @@ public class TraceEndpoint extends AbstractEndpoint> {
* @param repository the trace repository
*/
public TraceEndpoint(TraceRepository repository) {
- super("trace");
Assert.notNull(repository, "Repository must not be null");
this.repository = repository;
}
- @Override
- public List invoke() {
+ @ReadOperation
+ public List traces() {
return this.repository.findAll();
}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/AbstractJmxEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/AbstractJmxEndpoint.java
deleted file mode 100644
index d21ba8e6ea..0000000000
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/AbstractJmxEndpoint.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright 2012-2017 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.boot.actuate.endpoint.jmx;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-import org.springframework.boot.actuate.endpoint.Endpoint;
-import org.springframework.boot.actuate.endpoint.EndpointProperties;
-import org.springframework.context.EnvironmentAware;
-import org.springframework.core.env.Environment;
-import org.springframework.util.ObjectUtils;
-
-/**
- * Abstract base class for {@link JmxEndpoint} implementations without a backing
- * {@link Endpoint}.
- *
- * @author Vedran Pavic
- * @author Phillip Webb
- * @since 1.5.0
- */
-public abstract class AbstractJmxEndpoint implements JmxEndpoint, EnvironmentAware {
-
- private final DataConverter dataConverter;
-
- private Environment environment;
-
- /**
- * Enable the endpoint.
- */
- private Boolean enabled;
-
- public AbstractJmxEndpoint(ObjectMapper objectMapper) {
- this.dataConverter = new DataConverter(objectMapper);
- }
-
- @Override
- public void setEnvironment(Environment environment) {
- this.environment = environment;
- }
-
- protected final Environment getEnvironment() {
- return this.environment;
- }
-
- @Override
- public boolean isEnabled() {
- return EndpointProperties.isEnabled(this.environment, this.enabled);
- }
-
- public void setEnabled(Boolean enabled) {
- this.enabled = enabled;
- }
-
- @Override
- public String getIdentity() {
- return ObjectUtils.getIdentityHexString(this);
- }
-
- @Override
- @SuppressWarnings("rawtypes")
- public Class extends Endpoint> getEndpointType() {
- return null;
- }
-
- /**
- * Convert the given data into JSON.
- * @param data the source data
- * @return the JSON representation
- */
- protected Object convert(Object data) {
- return this.dataConverter.convert(data);
- }
-
-}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/AuditEventsJmxEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/AuditEventsJmxEndpoint.java
deleted file mode 100644
index d8690d09f5..0000000000
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/AuditEventsJmxEndpoint.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright 2012-2017 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.boot.actuate.endpoint.jmx;
-
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.List;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-import org.springframework.boot.actuate.audit.AuditEvent;
-import org.springframework.boot.actuate.audit.AuditEventRepository;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.jmx.export.annotation.ManagedOperation;
-import org.springframework.util.Assert;
-import org.springframework.util.StringUtils;
-
-/**
- * {@link JmxEndpoint} for {@link AuditEventRepository}.
- *
- * @author Vedran Pavic
- * @since 1.5.0
- */
-@ConfigurationProperties(prefix = "endpoints.auditevents")
-public class AuditEventsJmxEndpoint extends AbstractJmxEndpoint {
-
- private static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ssZ";
-
- private final AuditEventRepository auditEventRepository;
-
- public AuditEventsJmxEndpoint(ObjectMapper objectMapper,
- AuditEventRepository auditEventRepository) {
- super(objectMapper);
- Assert.notNull(auditEventRepository, "AuditEventRepository must not be null");
- this.auditEventRepository = auditEventRepository;
- }
-
- @ManagedOperation(description = "Retrieves a list of audit events meeting the given criteria")
- public Object getData(String dateAfter) {
- List auditEvents = this.auditEventRepository
- .find(parseDate(dateAfter));
- return convert(auditEvents);
- }
-
- @ManagedOperation(description = "Retrieves a list of audit events meeting the given criteria")
- public Object getData(String dateAfter, String principal) {
- List auditEvents = this.auditEventRepository.find(principal,
- parseDate(dateAfter));
- return convert(auditEvents);
- }
-
- @ManagedOperation(description = "Retrieves a list of audit events meeting the given criteria")
- public Object getData(String principal, String dateAfter, String type) {
- List auditEvents = this.auditEventRepository.find(principal,
- parseDate(dateAfter), type);
- return convert(auditEvents);
- }
-
- private Date parseDate(String date) {
- try {
- if (StringUtils.hasLength(date)) {
- return new SimpleDateFormat(DATE_FORMAT).parse(date);
- }
- return null;
- }
- catch (ParseException ex) {
- throw new IllegalArgumentException(ex);
- }
- }
-
-}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/AuditEventsJmxEndpointExtension.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/AuditEventsJmxEndpointExtension.java
new file mode 100644
index 0000000000..88629f32f9
--- /dev/null
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/AuditEventsJmxEndpointExtension.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2012-2017 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.boot.actuate.endpoint.jmx;
+
+import java.util.Date;
+import java.util.List;
+
+import org.springframework.boot.actuate.audit.AuditEvent;
+import org.springframework.boot.actuate.endpoint.AuditEventsEndpoint;
+import org.springframework.boot.endpoint.ReadOperation;
+import org.springframework.boot.endpoint.jmx.JmxEndpointExtension;
+
+/**
+ * JMX-specific extension of the {@link AuditEventsEndpoint}.
+ *
+ * @author Vedran Pavic
+ * @author Andy Wilkinson
+ * @since 2.0.0
+ */
+@JmxEndpointExtension(endpoint = AuditEventsEndpoint.class)
+public class AuditEventsJmxEndpointExtension {
+
+ private final AuditEventsEndpoint delegate;
+
+ public AuditEventsJmxEndpointExtension(AuditEventsEndpoint delegate) {
+ this.delegate = delegate;
+ }
+
+ @ReadOperation
+ public List eventsWithDateAfter(Date dateAfter) {
+ return this.delegate.eventsWithPrincipalDateAfterAndType(null, dateAfter, null);
+ }
+
+ @ReadOperation
+ public List eventsWithPrincipalAndDateAfter(String principal,
+ Date dateAfter) {
+ return this.delegate.eventsWithPrincipalDateAfterAndType(principal, dateAfter,
+ null);
+ }
+
+}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/DataConverter.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/DataConverter.java
deleted file mode 100644
index 0c519cc5b2..0000000000
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/DataConverter.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright 2012-2017 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.boot.actuate.endpoint.jmx;
-
-import java.util.List;
-import java.util.Map;
-
-import com.fasterxml.jackson.databind.JavaType;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-/**
- * Internal converter that uses an {@link ObjectMapper} to convert to JSON.
- *
- * @author Christian Dupuis
- * @author Andy Wilkinson
- * @author Phillip Webb
- */
-class DataConverter {
-
- private final ObjectMapper objectMapper;
-
- private final JavaType listObject;
-
- private final JavaType mapStringObject;
-
- DataConverter(ObjectMapper objectMapper) {
- this.objectMapper = (objectMapper == null ? new ObjectMapper() : objectMapper);
- this.listObject = this.objectMapper.getTypeFactory()
- .constructParametricType(List.class, Object.class);
- this.mapStringObject = this.objectMapper.getTypeFactory()
- .constructParametricType(Map.class, String.class, Object.class);
-
- }
-
- public Object convert(Object data) {
- if (data == null) {
- return null;
- }
- if (data instanceof String) {
- return data;
- }
- if (data.getClass().isArray() || data instanceof List) {
- return this.objectMapper.convertValue(data, this.listObject);
- }
- return this.objectMapper.convertValue(data, this.mapStringObject);
- }
-
-}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/DataEndpointMBean.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/DataEndpointMBean.java
deleted file mode 100644
index c3eccc8a0e..0000000000
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/DataEndpointMBean.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 2012-2017 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.boot.actuate.endpoint.jmx;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-import org.springframework.boot.actuate.endpoint.Endpoint;
-import org.springframework.jmx.export.annotation.ManagedAttribute;
-
-/**
- * Simple wrapper around {@link Endpoint} implementations that provide actuator data of
- * some sort.
- *
- * @author Christian Dupuis
- * @author Andy Wilkinson
- */
-public class DataEndpointMBean extends EndpointMBean {
-
- /**
- * Create a new {@link DataEndpointMBean} instance.
- * @param beanName the bean name
- * @param endpoint the endpoint to wrap
- * @param objectMapper the {@link ObjectMapper} used to convert the payload
- */
- public DataEndpointMBean(String beanName, Endpoint> endpoint,
- ObjectMapper objectMapper) {
- super(beanName, endpoint, objectMapper);
- }
-
- @ManagedAttribute(description = "Invoke the underlying endpoint")
- public Object getData() {
- return convert(getEndpoint().invoke());
- }
-
-}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/EndpointMBean.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/EndpointMBean.java
deleted file mode 100644
index ce6e3e71d7..0000000000
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/EndpointMBean.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright 2012-2017 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.boot.actuate.endpoint.jmx;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-import org.springframework.boot.actuate.endpoint.Endpoint;
-import org.springframework.jmx.export.annotation.ManagedAttribute;
-import org.springframework.util.Assert;
-import org.springframework.util.ClassUtils;
-import org.springframework.util.ObjectUtils;
-
-/**
- * Base for adapters that convert {@link Endpoint} implementations to {@link JmxEndpoint}.
- *
- * @author Christian Dupuis
- * @author Andy Wilkinson
- * @author Vedran Pavic
- * @author Phillip Webb
- * @see JmxEndpoint
- * @see DataEndpointMBean
- */
-public abstract class EndpointMBean implements JmxEndpoint {
-
- private final DataConverter dataConverter;
-
- private final Endpoint> endpoint;
-
- /**
- * Create a new {@link EndpointMBean} instance.
- * @param beanName the bean name
- * @param endpoint the endpoint to wrap
- * @param objectMapper the {@link ObjectMapper} used to convert the payload
- */
- public EndpointMBean(String beanName, Endpoint> endpoint,
- ObjectMapper objectMapper) {
- this.dataConverter = new DataConverter(objectMapper);
- Assert.notNull(beanName, "BeanName must not be null");
- Assert.notNull(endpoint, "Endpoint must not be null");
- this.endpoint = endpoint;
- }
-
- @ManagedAttribute(description = "Returns the class of the underlying endpoint")
- public String getEndpointClass() {
- return ClassUtils.getQualifiedName(getEndpointType());
- }
-
- @Override
- public boolean isEnabled() {
- return this.endpoint.isEnabled();
- }
-
- @Override
- public String getIdentity() {
- return ObjectUtils.getIdentityHexString(getEndpoint());
- }
-
- @Override
- @SuppressWarnings("rawtypes")
- public Class extends Endpoint> getEndpointType() {
- return getEndpoint().getClass();
- }
-
- public Endpoint> getEndpoint() {
- return this.endpoint;
- }
-
- /**
- * Convert the given data into JSON.
- * @param data the source data
- * @return the JSON representation
- */
- protected Object convert(Object data) {
- return this.dataConverter.convert(data);
- }
-
-}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/EndpointMBeanExporter.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/EndpointMBeanExporter.java
deleted file mode 100644
index 2907591d31..0000000000
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/EndpointMBeanExporter.java
+++ /dev/null
@@ -1,374 +0,0 @@
-/*
- * Copyright 2012-2017 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.boot.actuate.endpoint.jmx;
-
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Properties;
-import java.util.Set;
-import java.util.concurrent.locks.ReentrantLock;
-
-import javax.management.MBeanServer;
-import javax.management.MalformedObjectNameException;
-import javax.management.ObjectName;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import org.springframework.beans.BeansException;
-import org.springframework.beans.factory.BeanFactory;
-import org.springframework.beans.factory.ListableBeanFactory;
-import org.springframework.boot.actuate.endpoint.Endpoint;
-import org.springframework.boot.actuate.endpoint.LoggersEndpoint;
-import org.springframework.boot.actuate.endpoint.ShutdownEndpoint;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
-import org.springframework.context.SmartLifecycle;
-import org.springframework.core.annotation.AnnotationUtils;
-import org.springframework.jmx.export.MBeanExportException;
-import org.springframework.jmx.export.MBeanExporter;
-import org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource;
-import org.springframework.jmx.export.annotation.ManagedResource;
-import org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler;
-import org.springframework.jmx.export.metadata.InvalidMetadataException;
-import org.springframework.jmx.export.metadata.JmxAttributeSource;
-import org.springframework.jmx.export.naming.MetadataNamingStrategy;
-import org.springframework.jmx.export.naming.SelfNaming;
-import org.springframework.jmx.support.ObjectNameManager;
-import org.springframework.util.Assert;
-import org.springframework.util.ObjectUtils;
-
-/**
- * {@link SmartLifecycle} bean that registers all known {@link Endpoint}s with an
- * {@link MBeanServer} using the {@link MBeanExporter} located from the application
- * context.
- *
- * @author Christian Dupuis
- * @author Andy Wilkinson
- * @author Vedran Pavic
- */
-public class EndpointMBeanExporter extends MBeanExporter
- implements SmartLifecycle, ApplicationContextAware {
-
- /**
- * The default JMX domain.
- */
- public static final String DEFAULT_DOMAIN = "org.springframework.boot";
-
- private static final Log logger = LogFactory.getLog(EndpointMBeanExporter.class);
-
- private final AnnotationJmxAttributeSource attributeSource = new EndpointJmxAttributeSource();
-
- private final MetadataMBeanInfoAssembler assembler = new MetadataMBeanInfoAssembler(
- this.attributeSource);
-
- private final MetadataNamingStrategy defaultNamingStrategy = new MetadataNamingStrategy(
- this.attributeSource);
-
- private final Set> registeredEndpoints = new HashSet<>();
-
- private volatile boolean autoStartup = true;
-
- private volatile int phase = 0;
-
- private volatile boolean running = false;
-
- private final ReentrantLock lifecycleLock = new ReentrantLock();
-
- private ApplicationContext applicationContext;
-
- private ListableBeanFactory beanFactory;
-
- private String domain = DEFAULT_DOMAIN;
-
- private boolean ensureUniqueRuntimeObjectNames = false;
-
- private Properties objectNameStaticProperties = new Properties();
-
- private final ObjectMapper objectMapper;
-
- /**
- * Create a new {@link EndpointMBeanExporter} instance.
- */
- public EndpointMBeanExporter() {
- this(null);
- }
-
- /**
- * Create a new {@link EndpointMBeanExporter} instance.
- * @param objectMapper the object mapper
- */
- public EndpointMBeanExporter(ObjectMapper objectMapper) {
- this.objectMapper = (objectMapper == null ? new ObjectMapper() : objectMapper);
- setAutodetect(false);
- setNamingStrategy(this.defaultNamingStrategy);
- setAssembler(this.assembler);
- }
-
- @Override
- public void setApplicationContext(ApplicationContext applicationContext)
- throws BeansException {
- this.applicationContext = applicationContext;
- }
-
- @Override
- public void setBeanFactory(BeanFactory beanFactory) {
- super.setBeanFactory(beanFactory);
- if (beanFactory instanceof ListableBeanFactory) {
- this.beanFactory = (ListableBeanFactory) beanFactory;
- }
- else {
- logger.warn("EndpointMBeanExporter not running in a ListableBeanFactory: "
- + "autodetection of Endpoints not available.");
- }
- }
-
- public void setDomain(String domain) {
- this.domain = domain;
- }
-
- @Override
- public void setEnsureUniqueRuntimeObjectNames(
- boolean ensureUniqueRuntimeObjectNames) {
- super.setEnsureUniqueRuntimeObjectNames(ensureUniqueRuntimeObjectNames);
- this.ensureUniqueRuntimeObjectNames = ensureUniqueRuntimeObjectNames;
- }
-
- public void setObjectNameStaticProperties(Properties objectNameStaticProperties) {
- this.objectNameStaticProperties = objectNameStaticProperties;
- }
-
- protected void doStart() {
- locateAndRegisterEndpoints();
- }
-
- protected void locateAndRegisterEndpoints() {
- registerJmxEndpoints(this.beanFactory.getBeansOfType(JmxEndpoint.class));
- registerEndpoints(this.beanFactory.getBeansOfType(Endpoint.class));
- }
-
- private void registerJmxEndpoints(Map endpoints) {
- for (Map.Entry entry : endpoints.entrySet()) {
- String name = entry.getKey();
- JmxEndpoint endpoint = entry.getValue();
- Class> type = (endpoint.getEndpointType() != null
- ? endpoint.getEndpointType() : endpoint.getClass());
- if (!this.registeredEndpoints.contains(type) && endpoint.isEnabled()) {
- try {
- registerBeanNameOrInstance(endpoint, name);
- }
- catch (MBeanExportException ex) {
- logger.error("Could not register JmxEndpoint [" + name + "]", ex);
- }
- this.registeredEndpoints.add(type);
- }
- }
- }
-
- @SuppressWarnings("rawtypes")
- private void registerEndpoints(Map endpoints) {
- for (Map.Entry entry : endpoints.entrySet()) {
- String name = entry.getKey();
- Endpoint endpoint = entry.getValue();
- Class> type = endpoint.getClass();
- if (!this.registeredEndpoints.contains(type) && endpoint.isEnabled()) {
- registerEndpoint(name, endpoint);
- this.registeredEndpoints.add(type);
- }
- }
- }
-
- /**
- * Register a regular {@link Endpoint} with the {@link MBeanServer}.
- * @param beanName the bean name
- * @param endpoint the endpoint to register
- * @deprecated as of 1.5 in favor of direct {@link JmxEndpoint} registration or
- * {@link #adaptEndpoint(String, Endpoint)}
- */
- @Deprecated
- protected void registerEndpoint(String beanName, Endpoint> endpoint) {
- Class> type = endpoint.getClass();
- if (isAnnotatedWithManagedResource(type) || (type.isMemberClass()
- && isAnnotatedWithManagedResource(type.getEnclosingClass()))) {
- // Endpoint is directly managed
- return;
- }
- JmxEndpoint jmxEndpoint = adaptEndpoint(beanName, endpoint);
- try {
- registerBeanNameOrInstance(jmxEndpoint, beanName);
- }
- catch (MBeanExportException ex) {
- logger.error("Could not register MBean for endpoint [" + beanName + "]", ex);
- }
- }
-
- private boolean isAnnotatedWithManagedResource(Class> type) {
- return AnnotationUtils.findAnnotation(type, ManagedResource.class) != null;
- }
-
- /**
- * Adapt the given {@link Endpoint} to a {@link JmxEndpoint}.
- * @param beanName the bean name
- * @param endpoint the endpoint to adapt
- * @return an adapted endpoint
- */
- protected JmxEndpoint adaptEndpoint(String beanName, Endpoint> endpoint) {
- if (endpoint instanceof ShutdownEndpoint) {
- return new ShutdownEndpointMBean(beanName, endpoint, this.objectMapper);
- }
- if (endpoint instanceof LoggersEndpoint) {
- return new LoggersEndpointMBean(beanName, endpoint, this.objectMapper);
- }
- return new DataEndpointMBean(beanName, endpoint, this.objectMapper);
- }
-
- @Override
- protected ObjectName getObjectName(Object bean, String beanKey)
- throws MalformedObjectNameException {
- if (bean instanceof SelfNaming) {
- return ((SelfNaming) bean).getObjectName();
- }
- if (bean instanceof JmxEndpoint) {
- return getObjectName((JmxEndpoint) bean, beanKey);
- }
- return this.defaultNamingStrategy.getObjectName(bean, beanKey);
- }
-
- private ObjectName getObjectName(JmxEndpoint jmxEndpoint, String beanKey)
- throws MalformedObjectNameException {
- StringBuilder builder = new StringBuilder();
- builder.append(this.domain);
- builder.append(":type=Endpoint");
- builder.append(",name=" + beanKey);
- if (parentContextContainsSameBean(this.applicationContext, beanKey)) {
- builder.append(",context="
- + ObjectUtils.getIdentityHexString(this.applicationContext));
- }
- if (this.ensureUniqueRuntimeObjectNames) {
- builder.append(",identity=" + jmxEndpoint.getIdentity());
- }
- builder.append(getStaticNames());
- return ObjectNameManager.getInstance(builder.toString());
- }
-
- private boolean parentContextContainsSameBean(ApplicationContext applicationContext,
- String beanKey) {
- if (applicationContext.getParent() != null) {
- try {
- Object bean = this.applicationContext.getParent().getBean(beanKey);
- if (bean instanceof Endpoint || bean instanceof JmxEndpoint) {
- return true;
- }
- }
- catch (BeansException ex) {
- // Ignore and continue
- }
- return parentContextContainsSameBean(applicationContext.getParent(), beanKey);
- }
- return false;
- }
-
- private String getStaticNames() {
- if (this.objectNameStaticProperties.isEmpty()) {
- return "";
- }
- StringBuilder builder = new StringBuilder();
-
- for (Entry name : this.objectNameStaticProperties.entrySet()) {
- builder.append("," + name.getKey() + "=" + name.getValue());
- }
- return builder.toString();
- }
-
- @Override
- public final int getPhase() {
- return this.phase;
- }
-
- @Override
- public final boolean isAutoStartup() {
- return this.autoStartup;
- }
-
- @Override
- public final boolean isRunning() {
- this.lifecycleLock.lock();
- try {
- return this.running;
- }
- finally {
- this.lifecycleLock.unlock();
- }
- }
-
- @Override
- public final void start() {
- this.lifecycleLock.lock();
- try {
- if (!this.running) {
- this.doStart();
- this.running = true;
- }
- }
- finally {
- this.lifecycleLock.unlock();
- }
- }
-
- @Override
- public final void stop() {
- this.lifecycleLock.lock();
- try {
- if (this.running) {
- this.running = false;
- }
- }
- finally {
- this.lifecycleLock.unlock();
- }
- }
-
- @Override
- public final void stop(Runnable callback) {
- this.lifecycleLock.lock();
- try {
- this.stop();
- callback.run();
- }
- finally {
- this.lifecycleLock.unlock();
- }
- }
-
- /**
- * {@link JmxAttributeSource} for {@link JmxEndpoint JmxEndpoints}.
- */
- private static class EndpointJmxAttributeSource extends AnnotationJmxAttributeSource {
-
- @Override
- public org.springframework.jmx.export.metadata.ManagedResource getManagedResource(
- Class> beanClass) throws InvalidMetadataException {
- Assert.state(super.getManagedResource(beanClass) == null,
- "@ManagedResource annotation found on JmxEndpoint " + beanClass);
- return new org.springframework.jmx.export.metadata.ManagedResource();
- }
-
- }
-
-}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/JmxEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/JmxEndpoint.java
deleted file mode 100644
index 64a018eed0..0000000000
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/JmxEndpoint.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2012-2017 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.boot.actuate.endpoint.jmx;
-
-import org.springframework.boot.actuate.endpoint.Endpoint;
-import org.springframework.jmx.export.annotation.ManagedResource;
-
-/**
- * A strategy for the JMX layer on top of an {@link Endpoint}. Implementations are allowed
- * to use {@code @ManagedAttribute} and the full Spring JMX machinery but should not use
- * the {@link ManagedResource @ManagedResource} annotation. Implementations may be backed
- * by an actual {@link Endpoint} or may be specifically designed for JMX only.
- *
- * @author Phillip Webb
- * @since 1.5.0
- * @see EndpointMBean
- * @see AbstractJmxEndpoint
- */
-public interface JmxEndpoint {
-
- /**
- * Return if the JMX endpoint is enabled.
- * @return if the endpoint is enabled
- */
- boolean isEnabled();
-
- /**
- * Return the MBean identity for this endpoint.
- * @return the MBean identity.
- */
- String getIdentity();
-
- /**
- * Return the type of {@link Endpoint} exposed, or {@code null} if this
- * {@link JmxEndpoint} exposes information that cannot be represented as a traditional
- * {@link Endpoint}.
- * @return the endpoint type
- */
- @SuppressWarnings("rawtypes")
- Class extends Endpoint> getEndpointType();
-
-}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/LoggersEndpointMBean.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/LoggersEndpointMBean.java
deleted file mode 100644
index 9a5fc17082..0000000000
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/LoggersEndpointMBean.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright 2012-2017 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.boot.actuate.endpoint.jmx;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-import org.springframework.boot.actuate.endpoint.Endpoint;
-import org.springframework.boot.actuate.endpoint.LoggersEndpoint;
-import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
-import org.springframework.boot.logging.LogLevel;
-import org.springframework.jmx.export.annotation.ManagedAttribute;
-import org.springframework.jmx.export.annotation.ManagedOperation;
-import org.springframework.jmx.export.annotation.ManagedOperationParameter;
-import org.springframework.jmx.export.annotation.ManagedOperationParameters;
-import org.springframework.util.StringUtils;
-
-/**
- * Adapter to expose {@link LoggersEndpoint} as an {@link MvcEndpoint}.
- *
- * @author Vedran Pavic
- * @author Stephane Nicoll
- * @since 1.5.0
- */
-public class LoggersEndpointMBean extends EndpointMBean {
-
- public LoggersEndpointMBean(String beanName, Endpoint> endpoint,
- ObjectMapper objectMapper) {
- super(beanName, endpoint, objectMapper);
- }
-
- @ManagedAttribute(description = "Get log levels for all known loggers")
- public Object getLoggers() {
- return convert(getEndpoint().invoke());
- }
-
- @ManagedOperation(description = "Get log level for a given logger")
- @ManagedOperationParameters({
- @ManagedOperationParameter(name = "loggerName", description = "Name of the logger") })
- public Object getLogger(String loggerName) {
- return convert(getEndpoint().invoke(loggerName));
- }
-
- @ManagedOperation(description = "Set log level for a given logger")
- @ManagedOperationParameters({
- @ManagedOperationParameter(name = "loggerName", description = "Name of the logger"),
- @ManagedOperationParameter(name = "logLevel", description = "New log level (can be null or empty String to remove the custom level)") })
- public void setLogLevel(String loggerName, String logLevel) {
- getEndpoint().setLogLevel(loggerName, determineLogLevel(logLevel));
- }
-
- private LogLevel determineLogLevel(String logLevel) {
- if (StringUtils.hasText(logLevel)) {
- return LogLevel.valueOf(logLevel.toUpperCase());
- }
- return null;
- }
-
- @Override
- public LoggersEndpoint getEndpoint() {
- return (LoggersEndpoint) super.getEndpoint();
- }
-
-}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/ShutdownEndpointMBean.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/ShutdownEndpointMBean.java
deleted file mode 100644
index 8541086fe5..0000000000
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/ShutdownEndpointMBean.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 2012-2017 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.boot.actuate.endpoint.jmx;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-import org.springframework.boot.actuate.endpoint.Endpoint;
-import org.springframework.boot.actuate.endpoint.ShutdownEndpoint;
-import org.springframework.jmx.export.annotation.ManagedOperation;
-
-/**
- * Special endpoint wrapper for {@link ShutdownEndpoint}.
- *
- * @author Christian Dupuis
- * @author Andy Wilkinson
- */
-public class ShutdownEndpointMBean extends EndpointMBean {
-
- /**
- * Create a new {@link ShutdownEndpointMBean} instance.
- * @param beanName the bean name
- * @param endpoint the endpoint to wrap
- * @param objectMapper the {@link ObjectMapper} used to convert the payload
- */
- public ShutdownEndpointMBean(String beanName, Endpoint> endpoint,
- ObjectMapper objectMapper) {
- super(beanName, endpoint, objectMapper);
- }
-
- @ManagedOperation(description = "Shutdown the ApplicationContext")
- public Object shutdown() {
- return convert(getEndpoint().invoke());
- }
-
-}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/AbstractEndpointHandlerMapping.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/AbstractEndpointHandlerMapping.java
deleted file mode 100644
index 45b16f2fd8..0000000000
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/AbstractEndpointHandlerMapping.java
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * Copyright 2012-2017 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.boot.actuate.endpoint.mvc;
-
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.springframework.boot.actuate.endpoint.Endpoint;
-import org.springframework.context.ApplicationContext;
-import org.springframework.util.Assert;
-import org.springframework.util.ObjectUtils;
-import org.springframework.util.StringUtils;
-import org.springframework.web.accept.PathExtensionContentNegotiationStrategy;
-import org.springframework.web.cors.CorsConfiguration;
-import org.springframework.web.cors.CorsUtils;
-import org.springframework.web.servlet.HandlerExecutionChain;
-import org.springframework.web.servlet.HandlerInterceptor;
-import org.springframework.web.servlet.HandlerMapping;
-import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
-import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
-import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
-import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
-
-/**
- * {@link HandlerMapping} to map {@link Endpoint}s to URLs via {@link Endpoint#getId()}.
- * The semantics of {@code @RequestMapping} should be identical to a normal
- * {@code @Controller}, but the endpoints should not be annotated as {@code @Controller}
- * (otherwise they will be mapped by the normal MVC mechanisms).
- *
- * One of the aims of the mapping is to support endpoints that work as HTTP endpoints but
- * can still provide useful service interfaces when there is no HTTP server (and no Spring
- * MVC on the classpath). Note that any endpoints having method signatures will break in a
- * non-servlet environment.
- *
- * @param The endpoint type
- * @author Phillip Webb
- * @author Christian Dupuis
- * @author Dave Syer
- * @author Madhura Bhave
- */
-public abstract class AbstractEndpointHandlerMapping
- extends RequestMappingHandlerMapping {
-
- private final Set endpoints;
-
- private HandlerInterceptor securityInterceptor;
-
- private final CorsConfiguration corsConfiguration;
-
- private String prefix = "";
-
- private boolean disabled = false;
-
- /**
- * Create a new {@link AbstractEndpointHandlerMapping} instance. All {@link Endpoint}s
- * will be detected from the {@link ApplicationContext}. The endpoints will not accept
- * CORS requests.
- * @param endpoints the endpoints
- */
- public AbstractEndpointHandlerMapping(Collection extends E> endpoints) {
- this(endpoints, null);
- }
-
- /**
- * Create a new {@link AbstractEndpointHandlerMapping} instance. All {@link Endpoint}s
- * will be detected from the {@link ApplicationContext}. The endpoints will accepts
- * CORS requests based on the given {@code corsConfiguration}.
- * @param endpoints the endpoints
- * @param corsConfiguration the CORS configuration for the endpoints
- * @since 1.3.0
- */
- public AbstractEndpointHandlerMapping(Collection extends E> endpoints,
- CorsConfiguration corsConfiguration) {
- this.endpoints = new HashSet<>(endpoints);
- postProcessEndpoints(this.endpoints);
- this.corsConfiguration = corsConfiguration;
- // By default the static resource handler mapping is LOWEST_PRECEDENCE - 1
- // and the RequestMappingHandlerMapping is 0 (we ideally want to be before both)
- setOrder(-100);
- setUseSuffixPatternMatch(false);
- }
-
- /**
- * Post process the endpoint setting before they are used. Subclasses can add or
- * modify the endpoints as necessary.
- * @param endpoints the endpoints to post process
- */
- protected void postProcessEndpoints(Set endpoints) {
- }
-
- @Override
- public void afterPropertiesSet() {
- super.afterPropertiesSet();
- if (!this.disabled) {
- for (MvcEndpoint endpoint : this.endpoints) {
- detectHandlerMethods(endpoint);
- }
- }
- }
-
- /**
- * Since all handler beans are passed into the constructor there is no need to detect
- * anything here.
- */
- @Override
- protected boolean isHandler(Class> beanType) {
- return false;
- }
-
- @Override
- @Deprecated
- protected void registerHandlerMethod(Object handler, Method method,
- RequestMappingInfo mapping) {
- if (mapping == null) {
- return;
- }
- String[] patterns = getPatterns(handler, mapping);
- if (!ObjectUtils.isEmpty(patterns)) {
- super.registerHandlerMethod(handler, method,
- withNewPatterns(mapping, patterns));
- }
- }
-
- private String[] getPatterns(Object handler, RequestMappingInfo mapping) {
- if (handler instanceof String) {
- handler = getApplicationContext().getBean((String) handler);
- }
- Assert.state(handler instanceof MvcEndpoint, "Only MvcEndpoints are supported");
- String path = getPath((MvcEndpoint) handler);
- return (path == null ? null : getEndpointPatterns(path, mapping));
- }
-
- /**
- * Return the path that should be used to map the given {@link MvcEndpoint}.
- * @param endpoint the endpoint to map
- * @return the path to use for the endpoint or {@code null} if no mapping is required
- */
- protected String getPath(MvcEndpoint endpoint) {
- return endpoint.getPath();
- }
-
- private String[] getEndpointPatterns(String path, RequestMappingInfo mapping) {
- String patternPrefix = StringUtils.hasText(this.prefix) ? this.prefix + path
- : path;
- Set defaultPatterns = mapping.getPatternsCondition().getPatterns();
- if (defaultPatterns.isEmpty()) {
- return new String[] { patternPrefix, patternPrefix + ".json" };
- }
- List patterns = new ArrayList<>(defaultPatterns);
- for (int i = 0; i < patterns.size(); i++) {
- patterns.set(i, patternPrefix + patterns.get(i));
- }
- return patterns.toArray(new String[patterns.size()]);
- }
-
- private RequestMappingInfo withNewPatterns(RequestMappingInfo mapping,
- String[] patternStrings) {
- PatternsRequestCondition patterns = new PatternsRequestCondition(patternStrings,
- null, null, useSuffixPatternMatch(), useTrailingSlashMatch(), null);
- return new RequestMappingInfo(patterns, mapping.getMethodsCondition(),
- mapping.getParamsCondition(), mapping.getHeadersCondition(),
- mapping.getConsumesCondition(), mapping.getProducesCondition(),
- mapping.getCustomCondition());
- }
-
- @Override
- protected HandlerExecutionChain getHandlerExecutionChain(Object handler,
- HttpServletRequest request) {
- HandlerExecutionChain chain = super.getHandlerExecutionChain(handler, request);
- if (this.securityInterceptor == null || CorsUtils.isCorsRequest(request)) {
- return chain;
- }
- return addSecurityInterceptor(chain);
- }
-
- @Override
- protected HandlerExecutionChain getCorsHandlerExecutionChain(
- HttpServletRequest request, HandlerExecutionChain chain,
- CorsConfiguration config) {
- chain = super.getCorsHandlerExecutionChain(request, chain, config);
- if (this.securityInterceptor == null) {
- return chain;
- }
- return addSecurityInterceptor(chain);
- }
-
- @Override
- protected void extendInterceptors(List interceptors) {
- interceptors.add(new SkipPathExtensionContentNegotiation());
- }
-
- private HandlerExecutionChain addSecurityInterceptor(HandlerExecutionChain chain) {
- List interceptors = new ArrayList<>();
- if (chain.getInterceptors() != null) {
- interceptors.addAll(Arrays.asList(chain.getInterceptors()));
- }
- interceptors.add(this.securityInterceptor);
- return new HandlerExecutionChain(chain.getHandler(),
- interceptors.toArray(new HandlerInterceptor[interceptors.size()]));
- }
-
- /**
- * Set the handler interceptor that will be used for security.
- * @param securityInterceptor the security handler interceptor
- */
- public void setSecurityInterceptor(HandlerInterceptor securityInterceptor) {
- this.securityInterceptor = securityInterceptor;
- }
-
- /**
- * Set the prefix used in mappings.
- * @param prefix the prefix
- */
- public void setPrefix(String prefix) {
- Assert.isTrue("".equals(prefix) || StringUtils.startsWithIgnoreCase(prefix, "/"),
- "prefix must start with '/'");
- this.prefix = prefix;
- }
-
- /**
- * Get the prefix used in mappings.
- * @return the prefix
- */
- public String getPrefix() {
- return this.prefix;
- }
-
- /**
- * Get the path of the endpoint.
- * @param endpoint the endpoint
- * @return the path used in mappings
- */
- public String getPath(String endpoint) {
- return this.prefix + endpoint;
- }
-
- /**
- * Sets if this mapping is disabled.
- * @param disabled if the mapping is disabled
- */
- public void setDisabled(boolean disabled) {
- this.disabled = disabled;
- }
-
- /**
- * Returns if this mapping is disabled.
- * @return {@code true} if the mapping is disabled
- */
- public boolean isDisabled() {
- return this.disabled;
- }
-
- /**
- * Return the endpoints.
- * @return the endpoints
- */
- public Set getEndpoints() {
- return Collections.unmodifiableSet(this.endpoints);
- }
-
- @Override
- protected CorsConfiguration initCorsConfiguration(Object handler, Method method,
- RequestMappingInfo mappingInfo) {
- return this.corsConfiguration;
- }
-
- /**
- * {@link HandlerInterceptorAdapter} to ensure that
- * {@link PathExtensionContentNegotiationStrategy} is skipped for actuator endpoints.
- */
- private static final class SkipPathExtensionContentNegotiation
- extends HandlerInterceptorAdapter {
-
- private static final String SKIP_ATTRIBUTE = PathExtensionContentNegotiationStrategy.class
- .getName() + ".SKIP";
-
- @Override
- public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
- Object handler) throws Exception {
- request.setAttribute(SKIP_ATTRIBUTE, Boolean.TRUE);
- return true;
- }
-
- }
-
-}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/AbstractEndpointMvcAdapter.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/AbstractEndpointMvcAdapter.java
deleted file mode 100644
index f3e60d2123..0000000000
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/AbstractEndpointMvcAdapter.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright 2012-2016 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.boot.actuate.endpoint.mvc;
-
-import org.springframework.boot.actuate.endpoint.Endpoint;
-import org.springframework.http.ResponseEntity;
-import org.springframework.util.Assert;
-
-/**
- * Abstract base class for {@link MvcEndpoint} implementations.
- *
- * @param The delegate endpoint
- * @author Dave Syer
- * @author Andy Wilkinson
- * @author Phillip Webb
- * @since 1.3.0
- */
-public abstract class AbstractEndpointMvcAdapter>
- implements NamedMvcEndpoint {
-
- private final E delegate;
-
- /**
- * Endpoint URL path.
- */
- private String path;
-
- /**
- * Create a new {@link EndpointMvcAdapter}.
- * @param delegate the underlying {@link Endpoint} to adapt.
- */
- public AbstractEndpointMvcAdapter(E delegate) {
- Assert.notNull(delegate, "Delegate must not be null");
- this.delegate = delegate;
- }
-
- protected Object invoke() {
- if (!this.delegate.isEnabled()) {
- // Shouldn't happen - shouldn't be registered when delegate's disabled
- return getDisabledResponse();
- }
- return this.delegate.invoke();
- }
-
- public E getDelegate() {
- return this.delegate;
- }
-
- @Override
- public String getName() {
- return this.delegate.getId();
- }
-
- @Override
- public String getPath() {
- return (this.path != null ? this.path : "/" + this.delegate.getId());
- }
-
- public void setPath(String path) {
- while (path.endsWith("/")) {
- path = path.substring(0, path.length() - 1);
- }
- if (!path.startsWith("/")) {
- path = "/" + path;
- }
- this.path = path;
- }
-
- @Override
- @SuppressWarnings("rawtypes")
- public Class extends Endpoint> getEndpointType() {
- return this.delegate.getClass();
- }
-
- /**
- * Returns the response that should be returned when the endpoint is disabled.
- * @return The response to be returned when the endpoint is disabled
- * @since 1.2.4
- * @see Endpoint#isEnabled()
- */
- protected ResponseEntity> getDisabledResponse() {
- return MvcEndpoint.DISABLED_RESPONSE;
- }
-
-}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/AbstractMvcEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/AbstractMvcEndpoint.java
deleted file mode 100644
index efff32ed5c..0000000000
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/AbstractMvcEndpoint.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright 2012-2017 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.boot.actuate.endpoint.mvc;
-
-import org.springframework.boot.actuate.endpoint.Endpoint;
-import org.springframework.boot.actuate.endpoint.EndpointProperties;
-import org.springframework.context.EnvironmentAware;
-import org.springframework.core.env.Environment;
-import org.springframework.util.Assert;
-import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
-
-/**
- * Abstract base class for {@link MvcEndpoint} implementations without a backing
- * {@link Endpoint}.
- *
- * @author Phillip Webb
- * @author Lari Hotari
- * @since 1.4.0
- */
-public abstract class AbstractMvcEndpoint
- implements MvcEndpoint, WebMvcConfigurer, EnvironmentAware {
-
- private Environment environment;
-
- /**
- * Endpoint URL path.
- */
- private String path;
-
- /**
- * Enable the endpoint.
- */
- private Boolean enabled;
-
- public AbstractMvcEndpoint(String path) {
- setPath(path);
- }
-
- @Override
- public void setEnvironment(Environment environment) {
- this.environment = environment;
- }
-
- protected final Environment getEnvironment() {
- return this.environment;
- }
-
- @Override
- public String getPath() {
- return this.path;
- }
-
- public void setPath(String path) {
- Assert.notNull(path, "Path must not be null");
- Assert.isTrue(path.isEmpty() || path.startsWith("/"),
- "Path must start with / or be empty");
- this.path = path;
- }
-
- public boolean isEnabled() {
- return EndpointProperties.isEnabled(this.environment, this.enabled);
- }
-
- public void setEnabled(Boolean enabled) {
- this.enabled = enabled;
- }
-
- @Override
- @SuppressWarnings("rawtypes")
- public Class extends Endpoint> getEndpointType() {
- return null;
- }
-
-}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/AbstractNamedMvcEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/AbstractNamedMvcEndpoint.java
deleted file mode 100644
index 353070ad12..0000000000
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/AbstractNamedMvcEndpoint.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2012-2017 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.boot.actuate.endpoint.mvc;
-
-import org.springframework.boot.actuate.endpoint.Endpoint;
-import org.springframework.util.Assert;
-
-/**
- * Abstract base class for {@link NamedMvcEndpoint} implementations without a backing
- * {@link Endpoint}.
- *
- * @author Madhura Bhave
- * @since 1.5.0
- */
-public abstract class AbstractNamedMvcEndpoint extends AbstractMvcEndpoint
- implements NamedMvcEndpoint {
-
- private final String name;
-
- public AbstractNamedMvcEndpoint(String name, String path) {
- super(path);
- Assert.hasLength(name, "Name must not be empty");
- this.name = name;
- }
-
- @Override
- public String getName() {
- return this.name;
- }
-
-}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/ActuatorPostMapping.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/ActuatorPostMapping.java
deleted file mode 100644
index ff4746ba2d..0000000000
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/ActuatorPostMapping.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2012-2017 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.boot.actuate.endpoint.mvc;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-import org.springframework.core.annotation.AliasFor;
-import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-
-/**
- * Specialized {@link RequestMapping} for {@link RequestMethod#POST POST} requests that
- * consume {@code application/json} or
- * {@code application/vnd.spring-boot.actuator.v1+json} requests and produce
- * {@code application/json} or {@code application/vnd.spring-boot.actuator.v1+json}
- * responses.
- *
- * @author Andy Wilkinson
- */
-@Target(ElementType.METHOD)
-@Retention(RetentionPolicy.RUNTIME)
-@Documented
-@RequestMapping(method = RequestMethod.POST, consumes = {
- ActuatorMediaTypes.APPLICATION_ACTUATOR_V2_JSON_VALUE,
- MediaType.APPLICATION_JSON_VALUE }, produces = {
- ActuatorMediaTypes.APPLICATION_ACTUATOR_V2_JSON_VALUE,
- MediaType.APPLICATION_JSON_VALUE })
-@interface ActuatorPostMapping {
-
- /**
- * Alias for {@link RequestMapping#value}.
- * @return the value
- */
- @AliasFor(annotation = RequestMapping.class)
- String[] value() default {};
-
-}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/AuditEventsMvcEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/AuditEventsMvcEndpoint.java
deleted file mode 100644
index 38fce97c76..0000000000
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/AuditEventsMvcEndpoint.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2012-2017 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.boot.actuate.endpoint.mvc;
-
-import java.util.Date;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import org.springframework.boot.actuate.audit.AuditEvent;
-import org.springframework.boot.actuate.audit.AuditEventRepository;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.format.annotation.DateTimeFormat;
-import org.springframework.http.ResponseEntity;
-import org.springframework.util.Assert;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.ResponseBody;
-
-/**
- * {@link MvcEndpoint} to expose {@link AuditEvent}s.
- *
- * @author Vedran Pavic
- * @author Phillip Webb
- * @since 1.5.0
- */
-@ConfigurationProperties(prefix = "endpoints.auditevents")
-public class AuditEventsMvcEndpoint extends AbstractNamedMvcEndpoint {
-
- private final AuditEventRepository auditEventRepository;
-
- public AuditEventsMvcEndpoint(AuditEventRepository auditEventRepository) {
- super("auditevents", "/auditevents");
- Assert.notNull(auditEventRepository, "AuditEventRepository must not be null");
- this.auditEventRepository = auditEventRepository;
- }
-
- @ActuatorGetMapping
- @ResponseBody
- public ResponseEntity> findByPrincipalAndAfterAndType(
- @RequestParam(required = false) String principal,
- @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ssZ") Date after,
- @RequestParam(required = false) String type) {
- if (!isEnabled()) {
- return DISABLED_RESPONSE;
- }
- Map result = new LinkedHashMap<>();
- result.put("events", this.auditEventRepository.find(principal, after, type));
- return ResponseEntity.ok(result);
- }
-
-}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMapping.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMapping.java
deleted file mode 100644
index d5c153f427..0000000000
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMapping.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright 2012-2016 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.boot.actuate.endpoint.mvc;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import javax.servlet.http.HttpServletRequest;
-
-import org.springframework.boot.actuate.endpoint.Endpoint;
-import org.springframework.context.ApplicationContext;
-import org.springframework.web.bind.annotation.ResponseBody;
-import org.springframework.web.cors.CorsConfiguration;
-import org.springframework.web.servlet.HandlerMapping;
-
-/**
- * {@link HandlerMapping} to map {@link Endpoint}s to URLs via {@link Endpoint#getId()}.
- * The semantics of {@code @RequestMapping} should be identical to a normal
- * {@code @Controller}, but the endpoints should not be annotated as {@code @Controller}
- * (otherwise they will be mapped by the normal MVC mechanisms).
- *
- * One of the aims of the mapping is to support endpoints that work as HTTP endpoints but
- * can still provide useful service interfaces when there is no HTTP server (and no Spring
- * MVC on the classpath). Note that any endpoints having method signatures will break in a
- * non-servlet environment.
- *
- * @author Phillip Webb
- * @author Christian Dupuis
- * @author Dave Syer
- */
-public class EndpointHandlerMapping extends AbstractEndpointHandlerMapping {
-
- /**
- * Create a new {@link EndpointHandlerMapping} instance. All {@link Endpoint}s will be
- * detected from the {@link ApplicationContext}. The endpoints will not accept CORS
- * requests.
- * @param endpoints the endpoints
- */
- public EndpointHandlerMapping(Collection extends MvcEndpoint> endpoints) {
- super(endpoints);
- }
-
- /**
- * Create a new {@link EndpointHandlerMapping} instance. All {@link Endpoint}s will be
- * detected from the {@link ApplicationContext}. The endpoints will accepts CORS
- * requests based on the given {@code corsConfiguration}.
- * @param endpoints the endpoints
- * @param corsConfiguration the CORS configuration for the endpoints
- * @since 1.3.0
- */
- public EndpointHandlerMapping(Collection extends MvcEndpoint> endpoints,
- CorsConfiguration corsConfiguration) {
- super(endpoints, corsConfiguration);
- }
-
- @Override
- public void afterPropertiesSet() {
- super.afterPropertiesSet();
- detectHandlerMethods(new EndpointLinksMvcEndpoint(
- getEndpoints().stream().filter(NamedMvcEndpoint.class::isInstance)
- .map(NamedMvcEndpoint.class::cast).collect(Collectors.toSet())));
- }
-
- /**
- * {@link MvcEndpoint} to provide HAL-formatted links to all the
- * {@link NamedMvcEndpoint named endpoints}.
- *
- * @author Madhura Bhave
- * @author Andy Wilkinson
- */
- private static final class EndpointLinksMvcEndpoint extends AbstractMvcEndpoint {
-
- private final Set endpoints;
-
- private EndpointLinksMvcEndpoint(Set endpoints) {
- super("");
- this.endpoints = endpoints;
- }
-
- @ResponseBody
- @ActuatorGetMapping
- public Map> links(HttpServletRequest request) {
- Map links = new LinkedHashMap<>();
- String url = request.getRequestURL().toString();
- if (url.endsWith("/")) {
- url = url.substring(0, url.length() - 1);
- }
- links.put("self", Link.withHref(url));
- for (NamedMvcEndpoint endpoint : this.endpoints) {
- links.put(endpoint.getName(),
- Link.withHref(url + "/" + endpoint.getName()));
- }
- return Collections.singletonMap("_links", links);
- }
-
- }
-
- /**
- * Details for a link in the HAL response.
- */
- static final class Link {
-
- private final String href;
-
- private Link(String href) {
- this.href = href;
- }
-
- public String getHref() {
- return this.href;
- }
-
- static Link withHref(Object href) {
- return new Link(href.toString());
- }
-
- }
-
-}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EnvironmentMvcEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EnvironmentMvcEndpoint.java
deleted file mode 100644
index db35991038..0000000000
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EnvironmentMvcEndpoint.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright 2012-2017 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.boot.actuate.endpoint.mvc;
-
-import org.springframework.boot.actuate.endpoint.EnvironmentEndpoint;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.context.EnvironmentAware;
-import org.springframework.core.env.ConfigurableEnvironment;
-import org.springframework.core.env.EnumerablePropertySource;
-import org.springframework.core.env.Environment;
-import org.springframework.core.env.PropertySource;
-import org.springframework.core.env.PropertySources;
-import org.springframework.http.HttpStatus;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.ResponseBody;
-import org.springframework.web.bind.annotation.ResponseStatus;
-
-/**
- * Adapter to expose {@link EnvironmentEndpoint} as an {@link MvcEndpoint}.
- *
- * @author Dave Syer
- * @author Christian Dupuis
- * @author Andy Wilkinson
- */
-@ConfigurationProperties(prefix = "endpoints.env")
-public class EnvironmentMvcEndpoint extends EndpointMvcAdapter
- implements EnvironmentAware {
-
- private Environment environment;
-
- public EnvironmentMvcEndpoint(EnvironmentEndpoint delegate) {
- super(delegate);
- }
-
- @ActuatorGetMapping("/{name:.*}")
- @ResponseBody
- public Object value(@PathVariable String name) {
- if (!getDelegate().isEnabled()) {
- // Shouldn't happen - MVC endpoint shouldn't be registered when delegate's
- // disabled
- return getDisabledResponse();
- }
- return new NamePatternEnvironmentFilter(this.environment).getResults(name);
- }
-
- @Override
- public void setEnvironment(Environment environment) {
- this.environment = environment;
- }
-
- /**
- * {@link NamePatternFilter} for the Environment source.
- */
- private class NamePatternEnvironmentFilter extends NamePatternFilter {
-
- NamePatternEnvironmentFilter(Environment source) {
- super(source);
- }
-
- @Override
- protected void getNames(Environment source, NameCallback callback) {
- if (source instanceof ConfigurableEnvironment) {
- getNames(((ConfigurableEnvironment) source).getPropertySources(),
- callback);
- }
- }
-
- private void getNames(PropertySources propertySources, NameCallback callback) {
- for (PropertySource> propertySource : propertySources) {
- if (propertySource instanceof EnumerablePropertySource) {
- EnumerablePropertySource> source = (EnumerablePropertySource>) propertySource;
- for (String name : source.getPropertyNames()) {
- callback.addName(name);
- }
- }
- }
- }
-
- @Override
- protected Object getOptionalValue(Environment source, String name) {
- Object result = getValue(name);
- if (result != null) {
- result = ((EnvironmentEndpoint) getDelegate()).sanitize(name, result);
- }
- return result;
- }
-
- @Override
- protected Object getValue(Environment source, String name) {
- Object result = getValue(name);
- if (result == null) {
- throw new NoSuchPropertyException("No such property: " + name);
- }
- return ((EnvironmentEndpoint) getDelegate()).sanitize(name, result);
- }
-
- private Object getValue(String name) {
- return ((EnvironmentEndpoint) getDelegate()).getResolver().getProperty(name,
- Object.class);
- }
-
- }
-
- /**
- * Exception thrown when the specified property cannot be found.
- */
- @SuppressWarnings("serial")
- @ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "No such property")
- public static class NoSuchPropertyException extends RuntimeException {
-
- public NoSuchPropertyException(String string) {
- super(string);
- }
-
- }
-
-}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/HealthMvcEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/HealthMvcEndpoint.java
deleted file mode 100644
index de94480178..0000000000
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/HealthMvcEndpoint.java
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * Copyright 2012-2017 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.boot.actuate.endpoint.mvc;
-
-import java.security.Principal;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.servlet.http.HttpServletRequest;
-
-import org.springframework.boot.actuate.endpoint.HealthEndpoint;
-import org.springframework.boot.actuate.health.Health;
-import org.springframework.boot.actuate.health.Status;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.util.Assert;
-import org.springframework.util.ClassUtils;
-import org.springframework.web.bind.annotation.ResponseBody;
-
-/**
- * Adapter to expose {@link HealthEndpoint} as an {@link MvcEndpoint}.
- *
- * @author Christian Dupuis
- * @author Dave Syer
- * @author Andy Wilkinson
- * @author Phillip Webb
- * @author EddĂș MelĂ©ndez
- * @author Madhura Bhave
- * @since 1.1.0
- */
-@ConfigurationProperties(prefix = "endpoints.health")
-public class HealthMvcEndpoint extends AbstractEndpointMvcAdapter {
-
- private static final List DEFAULT_ROLES = Arrays.asList("ROLE_ACTUATOR");
-
- private final boolean secure;
-
- private final List roles;
-
- private Map statusMapping = new HashMap<>();
-
- private volatile CachedHealth cachedHealth;
-
- public HealthMvcEndpoint(HealthEndpoint delegate) {
- this(delegate, true);
- }
-
- public HealthMvcEndpoint(HealthEndpoint delegate, boolean secure) {
- this(delegate, secure, new ArrayList<>(DEFAULT_ROLES));
- }
-
- public HealthMvcEndpoint(HealthEndpoint delegate, boolean secure,
- List roles) {
- super(delegate);
- Assert.notNull(roles, "Roles must not be null");
- this.secure = secure;
- this.roles = roles;
- setupDefaultStatusMapping();
- }
-
- private void setupDefaultStatusMapping() {
- addStatusMapping(Status.DOWN, HttpStatus.SERVICE_UNAVAILABLE);
- addStatusMapping(Status.OUT_OF_SERVICE, HttpStatus.SERVICE_UNAVAILABLE);
- }
-
- /**
- * Set specific status mappings.
- * @param statusMapping a map of status code to {@link HttpStatus}
- */
- public void setStatusMapping(Map statusMapping) {
- Assert.notNull(statusMapping, "StatusMapping must not be null");
- this.statusMapping = new HashMap<>(statusMapping);
- }
-
- /**
- * Add specific status mappings to the existing set.
- * @param statusMapping a map of status code to {@link HttpStatus}
- */
- public void addStatusMapping(Map statusMapping) {
- Assert.notNull(statusMapping, "StatusMapping must not be null");
- this.statusMapping.putAll(statusMapping);
- }
-
- /**
- * Add a status mapping to the existing set.
- * @param status the status to map
- * @param httpStatus the http status
- */
- public void addStatusMapping(Status status, HttpStatus httpStatus) {
- Assert.notNull(status, "Status must not be null");
- Assert.notNull(httpStatus, "HttpStatus must not be null");
- addStatusMapping(status.getCode(), httpStatus);
- }
-
- /**
- * Add a status mapping to the existing set.
- * @param statusCode the status code to map
- * @param httpStatus the http status
- */
- public void addStatusMapping(String statusCode, HttpStatus httpStatus) {
- Assert.notNull(statusCode, "StatusCode must not be null");
- Assert.notNull(httpStatus, "HttpStatus must not be null");
- this.statusMapping.put(statusCode, httpStatus);
- }
-
- @ActuatorGetMapping
- @ResponseBody
- public Object invoke(HttpServletRequest request, Principal principal) {
- if (!getDelegate().isEnabled()) {
- // Shouldn't happen because the request mapping should not be registered
- return getDisabledResponse();
- }
- Health health = getHealth(request, principal);
- HttpStatus status = getStatus(health);
- if (status != null) {
- return new ResponseEntity<>(health, status);
- }
- return health;
- }
-
- private HttpStatus getStatus(Health health) {
- String code = getUniformValue(health.getStatus().getCode());
- if (code != null) {
- return this.statusMapping.keySet().stream()
- .filter((key) -> code.equals(getUniformValue(key)))
- .map(this.statusMapping::get).findFirst().orElse(null);
- }
- return null;
- }
-
- private String getUniformValue(String code) {
- if (code == null) {
- return null;
- }
- StringBuilder builder = new StringBuilder();
- for (char ch : code.toCharArray()) {
- if (Character.isAlphabetic(ch) || Character.isDigit(ch)) {
- builder.append(Character.toLowerCase(ch));
- }
- }
- return builder.toString();
- }
-
- private Health getHealth(HttpServletRequest request, Principal principal) {
- Health currentHealth = getCurrentHealth();
- if (exposeHealthDetails(request, principal)) {
- return currentHealth;
- }
- return Health.status(currentHealth.getStatus()).build();
- }
-
- private Health getCurrentHealth() {
- long accessTime = System.currentTimeMillis();
- CachedHealth cached = this.cachedHealth;
- if (cached == null || cached.isStale(accessTime, getDelegate().getTimeToLive())) {
- Health health = getDelegate().invoke();
- this.cachedHealth = new CachedHealth(health, accessTime);
- return health;
- }
- return cached.getHealth();
- }
-
- protected boolean exposeHealthDetails(HttpServletRequest request,
- Principal principal) {
- if (!this.secure) {
- return true;
- }
- List roles = getRoles();
- for (String role : roles) {
- if (request.isUserInRole(role)) {
- return true;
- }
- if (isSpringSecurityAuthentication(principal)) {
- Authentication authentication = (Authentication) principal;
- for (GrantedAuthority authority : authentication.getAuthorities()) {
- String name = authority.getAuthority();
- if (role.equals(name)) {
- return true;
- }
- }
- }
- }
- return false;
- }
-
- private List getRoles() {
- return this.roles;
- }
-
- private boolean isSpringSecurityAuthentication(Principal principal) {
- return ClassUtils.isPresent("org.springframework.security.core.Authentication",
- null) && principal instanceof Authentication;
- }
-
- /**
- * A cached {@link Health} that encapsulates the {@code Health} itself and the time at
- * which it was created.
- */
- static class CachedHealth {
-
- private final Health health;
-
- private final long creationTime;
-
- CachedHealth(Health health, long creationTime) {
- this.health = health;
- this.creationTime = creationTime;
- }
-
- public boolean isStale(long accessTime, long timeToLive) {
- return (accessTime - this.creationTime) >= timeToLive;
- }
-
- public Health getHealth() {
- return this.health;
- }
-
- }
-
-}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/LogFileMvcEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/LogFileMvcEndpoint.java
deleted file mode 100644
index 4971c86c12..0000000000
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/LogFileMvcEndpoint.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright 2012-2016 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.boot.actuate.endpoint.mvc;
-
-import java.io.File;
-import java.io.IOException;
-
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.boot.logging.LogFile;
-import org.springframework.core.io.FileSystemResource;
-import org.springframework.core.io.Resource;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
-
-/**
- * Controller that provides an API for logfiles, i.e. downloading the main logfile
- * configured in environment property 'logging.file' that is standard, but optional
- * property for spring-boot applications.
- *
- * @author Johannes Edmeier
- * @author Phillip Webb
- * @since 1.3.0
- */
-@ConfigurationProperties(prefix = "endpoints.logfile")
-public class LogFileMvcEndpoint extends AbstractNamedMvcEndpoint {
-
- private static final Log logger = LogFactory.getLog(LogFileMvcEndpoint.class);
-
- /**
- * External Logfile to be accessed. Can be used if the logfile is written by output
- * redirect and not by the logging-system itself.
- */
- private File externalFile;
-
- public LogFileMvcEndpoint() {
- super("logfile", "/logfile");
- }
-
- public File getExternalFile() {
- return this.externalFile;
- }
-
- public void setExternalFile(File externalFile) {
- this.externalFile = externalFile;
- }
-
- @RequestMapping(method = { RequestMethod.GET, RequestMethod.HEAD })
- public void invoke(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- if (!isEnabled()) {
- response.setStatus(HttpStatus.NOT_FOUND.value());
- return;
- }
- Resource resource = getLogFileResource();
- if (resource != null && !resource.exists()) {
- if (logger.isDebugEnabled()) {
- logger.debug("Log file '" + resource + "' does not exist");
- }
- resource = null;
- }
- Handler handler = new Handler(resource, request.getServletContext());
- handler.handleRequest(request, response);
- }
-
- private Resource getLogFileResource() {
- if (this.externalFile != null) {
- return new FileSystemResource(this.externalFile);
- }
- LogFile logFile = LogFile.get(getEnvironment());
- if (logFile == null) {
- logger.debug("Missing 'logging.file' or 'logging.path' properties");
- return null;
- }
- return new FileSystemResource(logFile.toString());
- }
-
- /**
- * {@link ResourceHttpRequestHandler} to send the log file.
- */
- private static class Handler extends ResourceHttpRequestHandler {
-
- private final Resource resource;
-
- Handler(Resource resource, ServletContext servletContext) {
- this.resource = resource;
- getLocations().add(resource);
- try {
- setServletContext(servletContext);
- afterPropertiesSet();
- }
- catch (Exception ex) {
- throw new IllegalStateException(ex);
- }
- }
-
- @Override
- protected void initAllowedLocations() {
- this.getLocations().clear();
- }
-
- @Override
- protected Resource getResource(HttpServletRequest request) throws IOException {
- return this.resource;
- }
-
- @Override
- protected MediaType getMediaType(HttpServletRequest request, Resource resource) {
- return MediaType.TEXT_PLAIN;
- }
-
- }
-
-}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/LoggersMvcEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/LoggersMvcEndpoint.java
deleted file mode 100644
index e603a20821..0000000000
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/LoggersMvcEndpoint.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright 2012-2017 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.boot.actuate.endpoint.mvc;
-
-import java.util.Map;
-
-import org.springframework.boot.actuate.endpoint.LoggersEndpoint;
-import org.springframework.boot.actuate.endpoint.LoggersEndpoint.LoggerLevels;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.boot.logging.LogLevel;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.ResponseBody;
-
-/**
- * Adapter to expose {@link LoggersEndpoint} as an {@link MvcEndpoint}.
- *
- * @author Ben Hale
- * @author Kazuki Shimizu
- * @author EddĂș MelĂ©ndez
- * @since 1.5.0
- */
-@ConfigurationProperties(prefix = "endpoints.loggers")
-public class LoggersMvcEndpoint extends EndpointMvcAdapter {
-
- private final LoggersEndpoint delegate;
-
- public LoggersMvcEndpoint(LoggersEndpoint delegate) {
- super(delegate);
- this.delegate = delegate;
- }
-
- @ActuatorGetMapping("/{name:.*}")
- @ResponseBody
- public Object get(@PathVariable String name) {
- if (!this.delegate.isEnabled()) {
- // Shouldn't happen - MVC endpoint shouldn't be registered when delegate's
- // disabled
- return getDisabledResponse();
- }
- LoggerLevels levels = this.delegate.invoke(name);
- return (levels == null ? ResponseEntity.notFound().build() : levels);
- }
-
- @ActuatorPostMapping("/{name:.*}")
- @ResponseBody
- public Object set(@PathVariable String name,
- @RequestBody Map configuration) {
- if (!this.delegate.isEnabled()) {
- // Shouldn't happen - MVC endpoint shouldn't be registered when delegate's
- // disabled
- return getDisabledResponse();
- }
- try {
- LogLevel logLevel = getLogLevel(configuration);
- this.delegate.setLogLevel(name, logLevel);
- return ResponseEntity.noContent().build();
- }
- catch (IllegalArgumentException ex) {
- return ResponseEntity.badRequest().build();
- }
- }
-
- private LogLevel getLogLevel(Map configuration) {
- String level = configuration.get("configuredLevel");
- return (level == null ? null : LogLevel.valueOf(level.toUpperCase()));
- }
-
-}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/ManagementErrorEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/ManagementErrorEndpoint.java
index 3eda218938..23389b9f9d 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/ManagementErrorEndpoint.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/ManagementErrorEndpoint.java
@@ -27,9 +27,9 @@ import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.ServletWebRequest;
/**
- * Special {@link MvcEndpoint} for handling "/error" path when the management servlet is
- * in a child context. The regular {@link ErrorController} should be available there but
- * because of the way the handler mappings are set up it will not be detected.
+ * {@link Controller} for handling "/error" path when the management servlet is in a child
+ * context. The regular {@link ErrorController} should be available there but because of
+ * the way the handler mappings are set up it will not be detected.
*
* @author Dave Syer
*/
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MetricsMvcEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MetricsMvcEndpoint.java
deleted file mode 100644
index bbf74a31ad..0000000000
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MetricsMvcEndpoint.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright 2012-2017 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.boot.actuate.endpoint.mvc;
-
-import java.util.Map;
-
-import org.springframework.boot.actuate.endpoint.MetricsEndpoint;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.http.HttpStatus;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.ResponseBody;
-import org.springframework.web.bind.annotation.ResponseStatus;
-
-/**
- * Adapter to expose {@link MetricsEndpoint} as an {@link MvcEndpoint}.
- *
- * @author Dave Syer
- * @author Andy Wilkinson
- * @author Sergei Egorov
- */
-@ConfigurationProperties(prefix = "endpoints.metrics")
-public class MetricsMvcEndpoint extends EndpointMvcAdapter {
-
- private final MetricsEndpoint delegate;
-
- public MetricsMvcEndpoint(MetricsEndpoint delegate) {
- super(delegate);
- this.delegate = delegate;
- }
-
- @ActuatorGetMapping("/{name:.*}")
- @ResponseBody
- public Object value(@PathVariable String name) {
- if (!this.delegate.isEnabled()) {
- // Shouldn't happen - MVC endpoint shouldn't be registered when delegate's
- // disabled
- return getDisabledResponse();
- }
- return new NamePatternMapFilter(this.delegate.invoke()).getResults(name);
- }
-
- /**
- * {@link NamePatternFilter} for the Map source.
- */
- private class NamePatternMapFilter extends NamePatternFilter> {
-
- NamePatternMapFilter(Map source) {
- super(source);
- }
-
- @Override
- protected void getNames(Map source, NameCallback callback) {
- for (String name : source.keySet()) {
- try {
- callback.addName(name);
- }
- catch (NoSuchMetricException ex) {
- // Metric with null value. Continue.
- }
- }
- }
-
- @Override
- protected Object getOptionalValue(Map source, String name) {
- return source.get(name);
- }
-
- @Override
- protected Object getValue(Map source, String name) {
- Object value = getOptionalValue(source, name);
- if (value == null) {
- throw new NoSuchMetricException("No such metric: " + name);
- }
- return value;
- }
-
- }
-
- /**
- * Exception thrown when the specified metric cannot be found.
- */
- @SuppressWarnings("serial")
- @ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "No such metric")
- public static class NoSuchMetricException extends RuntimeException {
-
- public NoSuchMetricException(String string) {
- super(string);
- }
-
- }
-
-}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpoint.java
deleted file mode 100644
index 969bfcfc90..0000000000
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpoint.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2012-2017 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.boot.actuate.endpoint.mvc;
-
-import java.util.Collections;
-import java.util.Map;
-
-import org.springframework.boot.actuate.endpoint.Endpoint;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-
-/**
- * A strategy for the MVC layer on top of an {@link Endpoint}. Implementations are allowed
- * to use {@code @RequestMapping} and the full Spring MVC machinery, but should not use
- * {@code @Controller} or {@code @RequestMapping} at the type level (since that would lead
- * to a double mapping of paths, once by the regular MVC handler mappings and once by the
- * {@link EndpointHandlerMapping}).
- *
- * @author Dave Syer
- * @see NamedMvcEndpoint
- */
-public interface MvcEndpoint {
-
- /**
- * A {@link ResponseEntity} returned for disabled endpoints.
- */
- ResponseEntity> DISABLED_RESPONSE = new ResponseEntity<>(
- Collections.singletonMap("message", "This endpoint is disabled"),
- HttpStatus.NOT_FOUND);
-
- /**
- * Return the MVC path of the endpoint.
- * @return the endpoint path
- */
- String getPath();
-
- /**
- * Return the type of {@link Endpoint} exposed, or {@code null} if this
- * {@link MvcEndpoint} exposes information that cannot be represented as a traditional
- * {@link Endpoint}.
- * @return the endpoint type
- */
- @SuppressWarnings("rawtypes")
- Class extends Endpoint> getEndpointType();
-
-}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpointSecurityInterceptor.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpointSecurityInterceptor.java
deleted file mode 100644
index 7430b36d5d..0000000000
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpointSecurityInterceptor.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright 2012-2017 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.boot.actuate.endpoint.mvc;
-
-import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import org.springframework.http.HttpMethod;
-import org.springframework.http.HttpStatus;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.util.ClassUtils;
-import org.springframework.util.StringUtils;
-import org.springframework.web.cors.CorsUtils;
-import org.springframework.web.method.HandlerMethod;
-import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
-
-/**
- * Security interceptor for MvcEndpoints.
- *
- * @author Madhura Bhave
- * @since 1.5.0
- */
-public class MvcEndpointSecurityInterceptor extends HandlerInterceptorAdapter {
-
- private static final Log logger = LogFactory
- .getLog(MvcEndpointSecurityInterceptor.class);
-
- private final boolean secure;
-
- private final List roles;
-
- private AtomicBoolean loggedUnauthorizedAttempt = new AtomicBoolean();
-
- public MvcEndpointSecurityInterceptor(boolean secure, List roles) {
- this.secure = secure;
- this.roles = roles;
- }
-
- @Override
- public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
- Object handler) throws Exception {
- if (CorsUtils.isPreFlightRequest(request) || !this.secure) {
- return true;
- }
- HandlerMethod handlerMethod = (HandlerMethod) handler;
- if (HttpMethod.OPTIONS.matches(request.getMethod())
- && !(handlerMethod.getBean() instanceof MvcEndpoint)) {
- return true;
- }
- if (isUserAllowedAccess(request)) {
- return true;
- }
- sendFailureResponse(request, response);
- return false;
- }
-
- private boolean isUserAllowedAccess(HttpServletRequest request) {
- AuthoritiesValidator authoritiesValidator = null;
- if (isSpringSecurityAvailable()) {
- authoritiesValidator = new AuthoritiesValidator();
- }
- for (String role : this.roles) {
- if (request.isUserInRole(role)) {
- return true;
- }
- if (authoritiesValidator != null && authoritiesValidator.hasAuthority(role)) {
- return true;
- }
- }
- return false;
- }
-
- private boolean isSpringSecurityAvailable() {
- return ClassUtils.isPresent(
- "org.springframework.security.config.annotation.web.WebSecurityConfigurer",
- getClass().getClassLoader());
- }
-
- private void sendFailureResponse(HttpServletRequest request,
- HttpServletResponse response) throws Exception {
- if (request.getUserPrincipal() != null) {
- String roles = StringUtils.collectionToDelimitedString(this.roles, " ");
- response.sendError(HttpStatus.FORBIDDEN.value(),
- "Access is denied. User must have one of the these roles: " + roles);
- }
- else {
- logUnauthorizedAttempt();
- response.sendError(HttpStatus.UNAUTHORIZED.value(),
- "Full authentication is required to access this resource.");
- }
- }
-
- private void logUnauthorizedAttempt() {
- if (this.loggedUnauthorizedAttempt.compareAndSet(false, true)
- && logger.isInfoEnabled()) {
- logger.info("Full authentication is required to access "
- + "actuator endpoints. Consider adding Spring Security "
- + "or set 'management.security.enabled' to false.");
- }
- }
-
- /**
- * Inner class to check authorities using Spring Security (when available).
- */
- private static class AuthoritiesValidator {
-
- private boolean hasAuthority(String role) {
- Authentication authentication = SecurityContextHolder.getContext()
- .getAuthentication();
- if (authentication != null) {
- for (GrantedAuthority authority : authentication.getAuthorities()) {
- if (authority.getAuthority().equals(role)) {
- return true;
- }
- }
- }
- return false;
- }
- }
-
-}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpoints.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpoints.java
deleted file mode 100644
index fe7d82dd0d..0000000000
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpoints.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright 2012-2017 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.boot.actuate.endpoint.mvc;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
-import org.springframework.beans.BeansException;
-import org.springframework.beans.factory.BeanFactoryUtils;
-import org.springframework.beans.factory.InitializingBean;
-import org.springframework.boot.actuate.endpoint.Endpoint;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
-import org.springframework.core.annotation.AnnotationUtils;
-import org.springframework.core.env.Environment;
-
-/**
- * A registry for all {@link MvcEndpoint} beans, and a factory for a set of generic ones
- * wrapping existing {@link Endpoint} instances that are not already exposed as MVC
- * endpoints.
- *
- * @author Dave Syer
- */
-public class MvcEndpoints implements ApplicationContextAware, InitializingBean {
-
- private ApplicationContext applicationContext;
-
- private final Set endpoints = new HashSet<>();
-
- private Set> customTypes;
-
- @Override
- public void setApplicationContext(ApplicationContext applicationContext)
- throws BeansException {
- this.applicationContext = applicationContext;
- }
-
- @Override
- public void afterPropertiesSet() throws Exception {
- Collection existing = BeanFactoryUtils
- .beansOfTypeIncludingAncestors(this.applicationContext, MvcEndpoint.class)
- .values();
- this.endpoints.addAll(existing);
- this.customTypes = findEndpointClasses(existing);
- @SuppressWarnings("rawtypes")
- Collection delegates = BeanFactoryUtils
- .beansOfTypeIncludingAncestors(this.applicationContext, Endpoint.class)
- .values();
- for (Endpoint> endpoint : delegates) {
- if (isGenericEndpoint(endpoint.getClass()) && endpoint.isEnabled()) {
- EndpointMvcAdapter adapter = new EndpointMvcAdapter(endpoint);
- String path = determinePath(endpoint,
- this.applicationContext.getEnvironment());
- if (path != null) {
- adapter.setPath(path);
- }
- this.endpoints.add(adapter);
- }
- }
- }
-
- private Set> findEndpointClasses(Collection existing) {
- Set> types = new HashSet<>();
- for (MvcEndpoint endpoint : existing) {
- Class> type = endpoint.getEndpointType();
- if (type != null) {
- types.add(type);
- }
- }
- return types;
- }
-
- public Set