Refactor actuator package locations
Restructure actuator packages to improve structure. The following changes have been made: - Separate actuator and actuator auto-configuration into different modules. - Move endpoint code into `spring-boot-actuator`. - Move `Endpoint` implementations from a single package into technology specific packages. - Move `HealthIndicator` implementations from a single package into technology specific packages. - As much as possible attempt to mirror the `spring-boot` package structure and class naming in `spring-boot-actuator` and `spring-boot-actuator-autoconfigure`. - Move `DataSourceBuilder` and DataSource meta-data support from `spring-boot-actuator` to `spring-boot`. Fixes gh-10261
This commit is contained in:
@@ -14,9 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.health;
|
||||
package org.springframework.boot.actuate.amqp;
|
||||
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -31,7 +34,7 @@ public class RabbitHealthIndicator extends AbstractHealthIndicator {
|
||||
private final RabbitTemplate rabbitTemplate;
|
||||
|
||||
public RabbitHealthIndicator(RabbitTemplate rabbitTemplate) {
|
||||
Assert.notNull(rabbitTemplate, "RabbitTemplate must not be null.");
|
||||
Assert.notNull(rabbitTemplate, "RabbitTemplate must not be null");
|
||||
this.rabbitTemplate = rabbitTemplate;
|
||||
}
|
||||
|
||||
@@ -14,15 +14,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.endpoint;
|
||||
package org.springframework.boot.actuate.audit;
|
||||
|
||||
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.boot.actuate.endpoint.annotation.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -14,14 +14,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.endpoint.jmx;
|
||||
package org.springframework.boot.actuate.audit;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.AuditEventsEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.AuditEventsEndpoint.AuditEventsDescriptor;
|
||||
import org.springframework.boot.endpoint.ReadOperation;
|
||||
import org.springframework.boot.endpoint.jmx.JmxEndpointExtension;
|
||||
import org.springframework.boot.actuate.audit.AuditEventsEndpoint.AuditEventsDescriptor;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
||||
import org.springframework.boot.actuate.endpoint.jmx.annotation.JmxEndpointExtension;
|
||||
|
||||
/**
|
||||
* JMX-specific extension of the {@link AuditEventsEndpoint}.
|
||||
@@ -1,251 +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;
|
||||
|
||||
import org.springframework.beans.factory.SmartInitializingSingleton;
|
||||
import org.springframework.boot.actuate.autoconfigure.web.ManagementServerProperties;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.ManagementServletContext;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
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.context.event.ApplicationFailedEvent;
|
||||
import org.springframework.boot.web.reactive.context.ConfigurableReactiveWebApplicationContext;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
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.Configuration;
|
||||
import org.springframework.context.event.ContextClosedEvent;
|
||||
import org.springframework.context.support.AbstractApplicationContext;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.context.ConfigurableWebApplicationContext;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for the management context. If the
|
||||
* {@code management.port} is the same as the {@code server.port} the management context
|
||||
* will be the same as the main application context. If the {@code management.port} is
|
||||
* different to the {@code server.port} the management context will be a separate context
|
||||
* that has the main application context as its parent.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE)
|
||||
public class ManagementContextAutoConfiguration {
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnWebApplication(type = Type.SERVLET)
|
||||
static class ServletManagementContextConfiguration {
|
||||
|
||||
@Bean
|
||||
public ManagementServletContext managementServletContext(
|
||||
ManagementServerProperties properties) {
|
||||
return () -> properties.getContextPath();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnManagementPort(ManagementPortType.SAME)
|
||||
static class SameManagementContextConfiguration
|
||||
implements SmartInitializingSingleton {
|
||||
|
||||
private final Environment environment;
|
||||
|
||||
SameManagementContextConfiguration(Environment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterSingletonsInstantiated() {
|
||||
verifySslConfiguration();
|
||||
if (this.environment instanceof ConfigurableEnvironment) {
|
||||
addLocalManagementPortPropertyAlias(
|
||||
(ConfigurableEnvironment) this.environment);
|
||||
}
|
||||
}
|
||||
|
||||
private void verifySslConfiguration() {
|
||||
Boolean enabled = this.environment.getProperty("management.ssl.enabled",
|
||||
Boolean.class, false);
|
||||
Assert.state(!enabled,
|
||||
"Management-specific SSL cannot be configured as the management "
|
||||
+ "server is not listening on a separate port");
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an alias for 'local.management.port' that actually resolves using
|
||||
* 'local.server.port'.
|
||||
* @param environment the environment
|
||||
*/
|
||||
private void addLocalManagementPortPropertyAlias(
|
||||
ConfigurableEnvironment environment) {
|
||||
environment.getPropertySources()
|
||||
.addLast(new PropertySource<Object>("Management Server") {
|
||||
|
||||
@Override
|
||||
public Object getProperty(String name) {
|
||||
if ("local.management.port".equals(name)) {
|
||||
return environment.getProperty("local.server.port");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@EnableManagementContext(ManagementContextType.SAME)
|
||||
static class EnableSameManagementContextConfiguration {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnManagementPort(ManagementPortType.DIFFERENT)
|
||||
static class SeparateManagementContextConfiguration
|
||||
implements SmartInitializingSingleton {
|
||||
|
||||
private final ApplicationContext applicationContext;
|
||||
|
||||
private final ManagementContextFactory managementContextFactory;
|
||||
|
||||
SeparateManagementContextConfiguration(ApplicationContext applicationContext,
|
||||
ManagementContextFactory managementContextFactory) {
|
||||
this.applicationContext = applicationContext;
|
||||
this.managementContextFactory = managementContextFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterSingletonsInstantiated() {
|
||||
ConfigurableApplicationContext managementContext = this.managementContextFactory
|
||||
.createManagementContext(this.applicationContext,
|
||||
EnableChildManagementContextConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class);
|
||||
setNamespaceIfPossible(managementContext);
|
||||
managementContext.setId(this.applicationContext.getId() + ":management");
|
||||
setClassLoaderIfPossible(managementContext);
|
||||
CloseManagementContextListener.addIfPossible(this.applicationContext,
|
||||
managementContext);
|
||||
managementContext.refresh();
|
||||
}
|
||||
|
||||
private void setClassLoaderIfPossible(ConfigurableApplicationContext child) {
|
||||
if (child instanceof DefaultResourceLoader) {
|
||||
((AbstractApplicationContext) child)
|
||||
.setClassLoader(this.applicationContext.getClassLoader());
|
||||
}
|
||||
}
|
||||
|
||||
private void setNamespaceIfPossible(ConfigurableApplicationContext child) {
|
||||
if (child instanceof ConfigurableReactiveWebApplicationContext) {
|
||||
((ConfigurableReactiveWebApplicationContext) child)
|
||||
.setNamespace("management");
|
||||
}
|
||||
else if (child instanceof ConfigurableWebApplicationContext) {
|
||||
((ConfigurableWebApplicationContext) child).setNamespace("management");
|
||||
}
|
||||
}
|
||||
|
||||
@ConditionalOnWebApplication(type = Type.SERVLET)
|
||||
static class ServletChildContextConfiguration {
|
||||
|
||||
@Bean
|
||||
public ServletWebManagementContextFactory servletWebChildContextFactory() {
|
||||
return new ServletWebManagementContextFactory();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnWebApplication(type = Type.REACTIVE)
|
||||
static class ReactiveChildContextConfiguration {
|
||||
|
||||
@Bean
|
||||
public ReactiveWebManagementContextFactory reactiveWebChildContextFactory() {
|
||||
return new ReactiveWebManagementContextFactory();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ApplicationListener} to propagate the {@link ContextClosedEvent} and
|
||||
* {@link ApplicationFailedEvent} from a parent to a child.
|
||||
*/
|
||||
private static class CloseManagementContextListener
|
||||
implements ApplicationListener<ApplicationEvent> {
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,57 +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;
|
||||
|
||||
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.Configuration;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
||||
/**
|
||||
* Specialized {@link Configuration @Configuration} class that defines configuration
|
||||
* specific for the management context. Configurations should be registered in
|
||||
* {@code /META-INF/spring.factories} under the
|
||||
* {@code org.springframework.boot.actuate.autoconfigure.ManagementContextConfiguration}
|
||||
* key.
|
||||
* <p>
|
||||
* {@code ManagementContextConfiguration} classes can be ordered using {@link Order}.
|
||||
* Ordering by implementing {@link Ordered} is not supported and will have no effect.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Configuration
|
||||
public @interface ManagementContextConfiguration {
|
||||
|
||||
/**
|
||||
* Specifies the type of management context that is required for this configuration to
|
||||
* be applied.
|
||||
* @return the required management context type
|
||||
* @since 2.0.0
|
||||
*/
|
||||
ManagementContextType value() default ManagementContextType.ANY;
|
||||
|
||||
}
|
||||
@@ -1,152 +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;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.context.annotation.DeferredImportSelector;
|
||||
import org.springframework.core.OrderComparator;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.core.type.classreading.MetadataReader;
|
||||
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
|
||||
|
||||
/**
|
||||
* Selects configuration classes for the management context configuration. Entries are
|
||||
* loaded from {@code /META-INF/spring.factories} under the
|
||||
* {@code org.springframework.boot.actuate.autoconfigure.ManagementContextConfiguration}
|
||||
* key.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
* @see ManagementContextConfiguration
|
||||
*/
|
||||
@Order(Ordered.LOWEST_PRECEDENCE)
|
||||
class ManagementContextConfigurationImportSelector
|
||||
implements DeferredImportSelector, BeanClassLoaderAware {
|
||||
|
||||
private ClassLoader classLoader;
|
||||
|
||||
@Override
|
||||
public String[] selectImports(AnnotationMetadata metadata) {
|
||||
ManagementContextType contextType = (ManagementContextType) metadata
|
||||
.getAnnotationAttributes(EnableManagementContext.class.getName())
|
||||
.get("value");
|
||||
// Find all management context configuration classes, filtering duplicates
|
||||
List<ManagementConfiguration> configurations = getConfigurations();
|
||||
OrderComparator.sort(configurations);
|
||||
List<String> names = new ArrayList<>();
|
||||
for (ManagementConfiguration configuration : configurations) {
|
||||
if (configuration.getContextType() == ManagementContextType.ANY
|
||||
|| configuration.getContextType() == contextType) {
|
||||
names.add(configuration.getClassName());
|
||||
}
|
||||
}
|
||||
return names.toArray(new String[names.size()]);
|
||||
}
|
||||
|
||||
private List<ManagementConfiguration> getConfigurations() {
|
||||
SimpleMetadataReaderFactory readerFactory = new SimpleMetadataReaderFactory(
|
||||
this.classLoader);
|
||||
List<ManagementConfiguration> configurations = new ArrayList<>();
|
||||
for (String className : loadFactoryNames()) {
|
||||
getConfiguration(readerFactory, configurations, className);
|
||||
}
|
||||
return configurations;
|
||||
}
|
||||
|
||||
private void getConfiguration(SimpleMetadataReaderFactory readerFactory,
|
||||
List<ManagementConfiguration> configurations, String className) {
|
||||
try {
|
||||
MetadataReader metadataReader = readerFactory.getMetadataReader(className);
|
||||
configurations.add(new ManagementConfiguration(metadataReader));
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new RuntimeException(
|
||||
"Failed to read annotation metadata for '" + className + "'", ex);
|
||||
}
|
||||
}
|
||||
|
||||
protected List<String> loadFactoryNames() {
|
||||
return SpringFactoriesLoader
|
||||
.loadFactoryNames(ManagementContextConfiguration.class, this.classLoader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* A management configuration class which can be sorted according to {@code @Order}.
|
||||
*/
|
||||
private static final class ManagementConfiguration implements Ordered {
|
||||
|
||||
private final String className;
|
||||
|
||||
private final int order;
|
||||
|
||||
private final ManagementContextType contextType;
|
||||
|
||||
ManagementConfiguration(MetadataReader metadataReader) {
|
||||
AnnotationMetadata annotationMetadata = metadataReader
|
||||
.getAnnotationMetadata();
|
||||
this.order = readOrder(annotationMetadata);
|
||||
this.className = metadataReader.getClassMetadata().getClassName();
|
||||
this.contextType = readContextType(annotationMetadata);
|
||||
}
|
||||
|
||||
private ManagementContextType readContextType(
|
||||
AnnotationMetadata annotationMetadata) {
|
||||
Map<String, Object> annotationAttributes = annotationMetadata
|
||||
.getAnnotationAttributes(
|
||||
ManagementContextConfiguration.class.getName());
|
||||
return (annotationAttributes == null ? ManagementContextType.ANY
|
||||
: (ManagementContextType) annotationAttributes.get("value"));
|
||||
}
|
||||
|
||||
private int readOrder(AnnotationMetadata annotationMetadata) {
|
||||
Map<String, Object> attributes = annotationMetadata
|
||||
.getAnnotationAttributes(Order.class.getName());
|
||||
Integer order = (attributes == null ? null
|
||||
: (Integer) attributes.get("value"));
|
||||
return (order == null ? Ordered.LOWEST_PRECEDENCE : order);
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
return this.className;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return this.order;
|
||||
}
|
||||
|
||||
public ManagementContextType getContextType() {
|
||||
return this.contextType;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,39 +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;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
|
||||
/**
|
||||
* A factory for creating a separate management context when the management web server is
|
||||
* running on a different port to the main application.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
interface ManagementContextFactory {
|
||||
|
||||
/**
|
||||
* Create the management application context.
|
||||
* @param parent the parent context
|
||||
* @param configurationClasses the configuration classes
|
||||
* @return a configured application context
|
||||
*/
|
||||
ConfigurableApplicationContext createManagementContext(ApplicationContext parent,
|
||||
Class<?>... configurationClasses);
|
||||
|
||||
}
|
||||
@@ -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.autoconfigure;
|
||||
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
/**
|
||||
* Port types that can be used to control how the management server is started.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public enum ManagementPortType {
|
||||
|
||||
/**
|
||||
* The management port has been disabled.
|
||||
*/
|
||||
DISABLED,
|
||||
|
||||
/**
|
||||
* The management port is the same as the server port.
|
||||
*/
|
||||
SAME,
|
||||
|
||||
/**
|
||||
* The management port and server port are different.
|
||||
*/
|
||||
DIFFERENT;
|
||||
|
||||
static ManagementPortType get(Environment environment) {
|
||||
Integer serverPort = getPortProperty(environment, "server.");
|
||||
Integer managementPort = getPortProperty(environment, "management.");
|
||||
if (managementPort != null && managementPort < 0) {
|
||||
return DISABLED;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,83 +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;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
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.ConditionContext;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
|
||||
/**
|
||||
* Base endpoint element condition. An element can be disabled globally via the
|
||||
* {@code defaults} name or individually via the name of the element.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Madhura Bhave
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public abstract class OnEnabledEndpointElementCondition extends SpringBootCondition {
|
||||
|
||||
private final String prefix;
|
||||
|
||||
private final Class<? extends Annotation> annotationType;
|
||||
|
||||
protected OnEnabledEndpointElementCondition(String prefix,
|
||||
Class<? extends Annotation> annotationType) {
|
||||
this.prefix = prefix;
|
||||
this.annotationType = annotationType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
AnnotationAttributes annotationAttributes = AnnotationAttributes
|
||||
.fromMap(metadata.getAnnotationAttributes(this.annotationType.getName()));
|
||||
String endpointName = annotationAttributes.getString("value");
|
||||
ConditionOutcome outcome = getEndpointOutcome(context, endpointName);
|
||||
if (outcome != null) {
|
||||
return outcome;
|
||||
}
|
||||
return getDefaultEndpointsOutcome(context);
|
||||
}
|
||||
|
||||
protected ConditionOutcome getEndpointOutcome(ConditionContext context,
|
||||
String endpointName) {
|
||||
Environment environment = context.getEnvironment();
|
||||
String enabledProperty = this.prefix + endpointName + ".enabled";
|
||||
if (environment.containsProperty(enabledProperty)) {
|
||||
boolean match = environment.getProperty(enabledProperty, Boolean.class, true);
|
||||
return new ConditionOutcome(match,
|
||||
ConditionMessage.forCondition(this.annotationType).because(
|
||||
this.prefix + endpointName + ".enabled is " + match));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected ConditionOutcome getDefaultEndpointsOutcome(ConditionContext context) {
|
||||
boolean match = Boolean.valueOf(context.getEnvironment()
|
||||
.getProperty(this.prefix + "defaults.enabled", "true"));
|
||||
return new ConditionOutcome(match,
|
||||
ConditionMessage.forCondition(this.annotationType).because(
|
||||
this.prefix + "defaults.enabled is considered " + match));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,75 +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;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
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.web.reactive.context.ConfigurableReactiveWebApplicationContext;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
/**
|
||||
* {@link SpringBootCondition} that matches when the management server is running on a
|
||||
* different port.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class OnManagementPortCondition extends SpringBootCondition {
|
||||
|
||||
private static final String CLASS_NAME_WEB_APPLICATION_CONTEXT = "org.springframework.web.context.WebApplicationContext";
|
||||
|
||||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
ConditionMessage.Builder message = ConditionMessage
|
||||
.forCondition("Management Port");
|
||||
if (!isWebApplicationContext(context)) {
|
||||
return ConditionOutcome
|
||||
.noMatch(message.because("non web application context"));
|
||||
}
|
||||
Map<String, Object> annotationAttributes = metadata
|
||||
.getAnnotationAttributes(ConditionalOnManagementPort.class.getName());
|
||||
ManagementPortType requiredType = (ManagementPortType) annotationAttributes
|
||||
.get("value");
|
||||
ManagementPortType actualType = ManagementPortType.get(context.getEnvironment());
|
||||
if (actualType == requiredType) {
|
||||
return ConditionOutcome.match(message.because(
|
||||
"actual port type (" + actualType + ") matched required type"));
|
||||
}
|
||||
return ConditionOutcome.noMatch(message.because("actual port type (" + actualType
|
||||
+ ") did not match required type (" + requiredType + ")"));
|
||||
}
|
||||
|
||||
private boolean isWebApplicationContext(ConditionContext context) {
|
||||
ResourceLoader resourceLoader = context.getResourceLoader();
|
||||
if (resourceLoader instanceof ConfigurableReactiveWebApplicationContext) {
|
||||
return true;
|
||||
}
|
||||
if (!ClassUtils.isPresent(CLASS_NAME_WEB_APPLICATION_CONTEXT,
|
||||
context.getClassLoader())) {
|
||||
return false;
|
||||
}
|
||||
return WebApplicationContext.class.isInstance(resourceLoader);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,85 +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;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import org.springframework.beans.FatalBeanException;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
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.autoconfigure.web.reactive.ReactiveWebServerAutoConfiguration;
|
||||
import org.springframework.boot.web.reactive.context.GenericReactiveWebApplicationContext;
|
||||
import org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext;
|
||||
import org.springframework.boot.web.reactive.server.ReactiveWebServerFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
|
||||
/**
|
||||
* A {@link ManagementContextFactory} for WebFlux-based web applications.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class ReactiveWebManagementContextFactory implements ManagementContextFactory {
|
||||
|
||||
@Override
|
||||
public ConfigurableApplicationContext createManagementContext(
|
||||
ApplicationContext parent, Class<?>... configClasses) {
|
||||
ReactiveWebServerApplicationContext child = new ReactiveWebServerApplicationContext();
|
||||
child.setParent(parent);
|
||||
child.register(configClasses);
|
||||
child.register(ReactiveWebServerAutoConfiguration.class);
|
||||
registerReactiveWebServerFactory(parent, child);
|
||||
return child;
|
||||
}
|
||||
|
||||
private void registerReactiveWebServerFactory(ApplicationContext parent,
|
||||
GenericReactiveWebApplicationContext childContext) {
|
||||
try {
|
||||
ConfigurableListableBeanFactory beanFactory = childContext.getBeanFactory();
|
||||
if (beanFactory instanceof BeanDefinitionRegistry) {
|
||||
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
|
||||
registry.registerBeanDefinition("ReactiveWebServerFactory",
|
||||
new RootBeanDefinition(
|
||||
determineReactiveWebServerFactoryClass(parent)));
|
||||
}
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
// Ignore and assume auto-configuration
|
||||
}
|
||||
}
|
||||
|
||||
private Class<?> determineReactiveWebServerFactoryClass(ApplicationContext parent)
|
||||
throws NoSuchBeanDefinitionException {
|
||||
Class<?> factoryClass = parent.getBean(ReactiveWebServerFactory.class).getClass();
|
||||
if (cannotBeInstantiated(factoryClass)) {
|
||||
throw new FatalBeanException("ReactiveWebServerFactory 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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.FatalBeanException;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
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.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
|
||||
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
|
||||
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
|
||||
/**
|
||||
* A {@link ManagementContextFactory} for servlet-based web applications.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class ServletWebManagementContextFactory implements ManagementContextFactory {
|
||||
|
||||
@Override
|
||||
public ConfigurableApplicationContext createManagementContext(
|
||||
ApplicationContext parent, Class<?>... configClasses) {
|
||||
AnnotationConfigServletWebServerApplicationContext child = new AnnotationConfigServletWebServerApplicationContext();
|
||||
child.setParent(parent);
|
||||
List<Class<?>> combinedClasses = new ArrayList<>(Arrays.asList(configClasses));
|
||||
combinedClasses.add(ServletWebServerFactoryAutoConfiguration.class);
|
||||
child.register(combinedClasses.toArray(new Class<?>[combinedClasses.size()]));
|
||||
registerServletWebServerFactory(parent, child);
|
||||
return child;
|
||||
}
|
||||
|
||||
private void registerServletWebServerFactory(ApplicationContext parent,
|
||||
AnnotationConfigServletWebServerApplicationContext childContext) {
|
||||
try {
|
||||
ConfigurableListableBeanFactory beanFactory = childContext.getBeanFactory();
|
||||
if (beanFactory instanceof BeanDefinitionRegistry) {
|
||||
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
|
||||
registry.registerBeanDefinition("ServletWebServerFactory",
|
||||
new RootBeanDefinition(
|
||||
determineServletWebServerFactoryClass(parent)));
|
||||
}
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
// Ignore and assume auto-configuration
|
||||
}
|
||||
}
|
||||
|
||||
private Class<?> determineServletWebServerFactoryClass(ApplicationContext parent)
|
||||
throws NoSuchBeanDefinitionException {
|
||||
Class<?> factoryClass = parent.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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,82 +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.audit;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.actuate.audit.AuditEvent;
|
||||
import org.springframework.boot.actuate.audit.AuditEventRepository;
|
||||
import org.springframework.boot.actuate.audit.InMemoryAuditEventRepository;
|
||||
import org.springframework.boot.actuate.audit.listener.AbstractAuditListener;
|
||||
import org.springframework.boot.actuate.audit.listener.AuditListener;
|
||||
import org.springframework.boot.actuate.security.AbstractAuthenticationAuditListener;
|
||||
import org.springframework.boot.actuate.security.AbstractAuthorizationAuditListener;
|
||||
import org.springframework.boot.actuate.security.AuthenticationAuditListener;
|
||||
import org.springframework.boot.actuate.security.AuthorizationAuditListener;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for {@link AuditEvent}s.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Vedran Pavic
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration
|
||||
public class AuditAutoConfiguration {
|
||||
|
||||
private final AuditEventRepository auditEventRepository;
|
||||
|
||||
public AuditAutoConfiguration(
|
||||
ObjectProvider<AuditEventRepository> auditEventRepository) {
|
||||
this.auditEventRepository = auditEventRepository.getIfAvailable();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(AbstractAuditListener.class)
|
||||
public AuditListener auditListener() throws Exception {
|
||||
return new AuditListener(this.auditEventRepository);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnClass(name = "org.springframework.security.authentication.event.AbstractAuthenticationEvent")
|
||||
@ConditionalOnMissingBean(AbstractAuthenticationAuditListener.class)
|
||||
public AuthenticationAuditListener authenticationAuditListener() throws Exception {
|
||||
return new AuthenticationAuditListener();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnClass(name = "org.springframework.security.access.event.AbstractAuthorizationEvent")
|
||||
@ConditionalOnMissingBean(AbstractAuthorizationAuditListener.class)
|
||||
public AuthorizationAuditListener authorizationAuditListener() throws Exception {
|
||||
return new AuthorizationAuditListener();
|
||||
}
|
||||
|
||||
@ConditionalOnMissingBean(AuditEventRepository.class)
|
||||
protected static class AuditEventRepositoryConfiguration {
|
||||
|
||||
@Bean
|
||||
public InMemoryAuditEventRepository auditEventRepository() throws Exception {
|
||||
return new InMemoryAuditEventRepository();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,150 +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.cache;
|
||||
|
||||
import javax.cache.Caching;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.hazelcast.core.IMap;
|
||||
import com.hazelcast.spring.cache.HazelcastCache;
|
||||
import net.sf.ehcache.Ehcache;
|
||||
import net.sf.ehcache.statistics.StatisticsGateway;
|
||||
import org.infinispan.spring.provider.SpringCache;
|
||||
|
||||
import org.springframework.boot.actuate.cache.CacheStatistics;
|
||||
import org.springframework.boot.actuate.cache.CacheStatisticsProvider;
|
||||
import org.springframework.boot.actuate.cache.CaffeineCacheStatisticsProvider;
|
||||
import org.springframework.boot.actuate.cache.ConcurrentMapCacheStatisticsProvider;
|
||||
import org.springframework.boot.actuate.cache.DefaultCacheStatistics;
|
||||
import org.springframework.boot.actuate.cache.EhCacheStatisticsProvider;
|
||||
import org.springframework.boot.actuate.cache.HazelcastCacheStatisticsProvider;
|
||||
import org.springframework.boot.actuate.cache.InfinispanCacheStatisticsProvider;
|
||||
import org.springframework.boot.actuate.cache.JCacheCacheStatisticsProvider;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.caffeine.CaffeineCacheManager;
|
||||
import org.springframework.cache.concurrent.ConcurrentMapCache;
|
||||
import org.springframework.cache.ehcache.EhCacheCache;
|
||||
import org.springframework.cache.jcache.JCacheCache;
|
||||
import org.springframework.cache.support.NoOpCacheManager;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for {@link CacheStatisticsProvider}
|
||||
* beans.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Phillip Webb
|
||||
* @author Eddú Meléndez
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@AutoConfigureAfter(CacheAutoConfiguration.class)
|
||||
@ConditionalOnBean(CacheManager.class)
|
||||
public class CacheStatisticsAutoConfiguration {
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass({ Caching.class, JCacheCache.class })
|
||||
static class JCacheCacheStatisticsProviderConfiguration {
|
||||
|
||||
@Bean
|
||||
public JCacheCacheStatisticsProvider jCacheCacheStatisticsProvider() {
|
||||
return new JCacheCacheStatisticsProvider();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass({ EhCacheCache.class, Ehcache.class, StatisticsGateway.class })
|
||||
static class EhCacheCacheStatisticsProviderConfiguration {
|
||||
|
||||
@Bean
|
||||
public EhCacheStatisticsProvider ehCacheCacheStatisticsProvider() {
|
||||
return new EhCacheStatisticsProvider();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass({ IMap.class, HazelcastCache.class })
|
||||
static class HazelcastCacheStatisticsConfiguration {
|
||||
|
||||
@Bean
|
||||
public HazelcastCacheStatisticsProvider hazelcastCacheStatisticsProvider() {
|
||||
return new HazelcastCacheStatisticsProvider();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass({ SpringCache.class })
|
||||
static class InfinispanCacheStatisticsProviderConfiguration {
|
||||
|
||||
@Bean
|
||||
public InfinispanCacheStatisticsProvider infinispanCacheStatisticsProvider() {
|
||||
return new InfinispanCacheStatisticsProvider();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass({ Caffeine.class, CaffeineCacheManager.class })
|
||||
static class CaffeineCacheStatisticsProviderConfiguration {
|
||||
|
||||
@Bean
|
||||
public CaffeineCacheStatisticsProvider caffeineCacheStatisticsProvider() {
|
||||
return new CaffeineCacheStatisticsProvider();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(ConcurrentMapCache.class)
|
||||
static class ConcurrentMapCacheStatisticsConfiguration {
|
||||
|
||||
@Bean
|
||||
public ConcurrentMapCacheStatisticsProvider concurrentMapCacheStatisticsProvider() {
|
||||
return new ConcurrentMapCacheStatisticsProvider();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(NoOpCacheManager.class)
|
||||
static class NoOpCacheStatisticsConfiguration {
|
||||
|
||||
private static final CacheStatistics NO_OP_STATS = new DefaultCacheStatistics();
|
||||
|
||||
@Bean
|
||||
public CacheStatisticsProvider<Cache> noOpCacheStatisticsProvider() {
|
||||
return (cacheManager, cache) -> {
|
||||
if (cacheManager instanceof NoOpCacheManager) {
|
||||
return NO_OP_STATS;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,76 +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.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.boot.endpoint.Endpoint;
|
||||
import org.springframework.boot.endpoint.EndpointExposure;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
|
||||
/**
|
||||
* {@link Conditional} that checks whether an endpoint is enabled or not. Matches
|
||||
* according to the {@code enabledByDefault} flag {@code types} flag that the
|
||||
* {@link Endpoint} may be restricted to.
|
||||
* <p>
|
||||
* If no specific {@code endpoints.<id>.*} or {@code endpoints.default.*} properties are
|
||||
* defined, the condition matches the {@code enabledByDefault} value regardless of the
|
||||
* specific {@link EndpointExposure}, if any. If any property are set, they are evaluated
|
||||
* with a sensible order of precedence.
|
||||
* <p>
|
||||
* For instance if {@code endpoints.default.enabled} is {@code false} but
|
||||
* {@code endpoints.<id>.enabled} is {@code true}, the condition will match.
|
||||
* <p>
|
||||
* 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:
|
||||
*
|
||||
* <pre class="code">
|
||||
* @Configuration
|
||||
* public class MyAutoConfiguration {
|
||||
*
|
||||
* @ConditionalOnEnabledEndpoint
|
||||
* @Bean
|
||||
* public MyEndpoint myEndpoint() {
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* @Endpoint(id = "my", enabledByDefault = false)
|
||||
* static class MyEndpoint { ... }
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
*
|
||||
* 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 {
|
||||
|
||||
}
|
||||
@@ -1,305 +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.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
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.EnvironmentEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.FlywayEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.HealthEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.InfoEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.LiquibaseEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.LoggersEndpoint;
|
||||
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.StatusEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.ThreadDumpEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.TraceEndpoint;
|
||||
import org.springframework.boot.actuate.health.CompositeHealthIndicatorFactory;
|
||||
import org.springframework.boot.actuate.health.HealthAggregator;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.OrderedHealthAggregator;
|
||||
import org.springframework.boot.actuate.health.ReactiveHealthIndicator;
|
||||
import org.springframework.boot.actuate.info.InfoContributor;
|
||||
import org.springframework.boot.actuate.trace.InMemoryTraceRepository;
|
||||
import org.springframework.boot.actuate.trace.TraceRepository;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;
|
||||
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.ConditionalOnMissingClass;
|
||||
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.endpoint.Endpoint;
|
||||
import org.springframework.boot.logging.LoggingSystem;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for common management
|
||||
* {@link Endpoint}s.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Phillip Webb
|
||||
* @author Greg Turnquist
|
||||
* @author Christian Dupuis
|
||||
* @author Stephane Nicoll
|
||||
* @author Eddú Meléndez
|
||||
* @author Meang Akira Tanaka
|
||||
* @author Ben Hale
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@AutoConfigureAfter({ FlywayAutoConfiguration.class, LiquibaseAutoConfiguration.class })
|
||||
public class EndpointAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnEnabledEndpoint
|
||||
public EnvironmentEndpoint environmentEndpoint(Environment environment) {
|
||||
return new EnvironmentEndpoint(environment);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnEnabledEndpoint
|
||||
public BeansEndpoint beansEndpoint(
|
||||
ConfigurableApplicationContext applicationContext) {
|
||||
return new BeansEndpoint(applicationContext);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnEnabledEndpoint
|
||||
public InfoEndpoint infoEndpoint(
|
||||
ObjectProvider<List<InfoContributor>> 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
|
||||
@ConditionalOnEnabledEndpoint
|
||||
public MetricsEndpoint metricsEndpoint(
|
||||
ObjectProvider<List<PublicMetrics>> publicMetrics) {
|
||||
List<PublicMetrics> sortedPublicMetrics = publicMetrics
|
||||
.getIfAvailable(Collections::emptyList);
|
||||
Collections.sort(sortedPublicMetrics, AnnotationAwareOrderComparator.INSTANCE);
|
||||
return new MetricsEndpoint(sortedPublicMetrics);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnEnabledEndpoint
|
||||
public TraceEndpoint traceEndpoint(ObjectProvider<TraceRepository> traceRepository) {
|
||||
return new TraceEndpoint(
|
||||
traceRepository.getIfAvailable(() -> new InMemoryTraceRepository()));
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnEnabledEndpoint
|
||||
public ThreadDumpEndpoint dumpEndpoint() {
|
||||
return new ThreadDumpEndpoint();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(ConditionEvaluationReport.class)
|
||||
@ConditionalOnMissingBean(search = SearchStrategy.CURRENT)
|
||||
@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
|
||||
@Import(HealthIndicatorsSupplierConfiguration.class)
|
||||
static class HealthEndpointConfiguration {
|
||||
|
||||
private final HealthIndicator healthIndicator;
|
||||
|
||||
HealthEndpointConfiguration(ObjectProvider<HealthAggregator> healthAggregator,
|
||||
Supplier<Map<String, HealthIndicator>> healthIndicatorsSupplier) {
|
||||
this.healthIndicator = new CompositeHealthIndicatorFactory()
|
||||
.createHealthIndicator(
|
||||
healthAggregator.getIfAvailable(OrderedHealthAggregator::new),
|
||||
healthIndicatorsSupplier.get());
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnEnabledEndpoint
|
||||
public HealthEndpoint healthEndpoint() {
|
||||
return new HealthEndpoint(this.healthIndicator);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnEnabledEndpoint
|
||||
public StatusEndpoint statusEndpoint() {
|
||||
return new StatusEndpoint(this.healthIndicator);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class HealthIndicatorsSupplierConfiguration {
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnMissingClass("reactor.core.publisher.Flux")
|
||||
static class SimpleHealthIndicatorsSupplierConfiguration {
|
||||
|
||||
@Bean
|
||||
public Supplier<Map<String, HealthIndicator>> allHealthIndicators(
|
||||
ObjectProvider<Map<String, HealthIndicator>> healthIndicators) {
|
||||
return () -> healthIndicators.getIfAvailable(Collections::emptyMap);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(name = "reactor.core.publisher.Flux")
|
||||
static class ReactiveHealthIndicatorsSupplierConfiguration {
|
||||
|
||||
@Bean
|
||||
public Supplier<Map<String, HealthIndicator>> allHealthIndicators(
|
||||
ObjectProvider<Map<String, HealthIndicator>> healthIndicators,
|
||||
ObjectProvider<Map<String, ReactiveHealthIndicator>> reactiveHealthIndicators) {
|
||||
return () -> merge(healthIndicators.getIfAvailable(Collections::emptyMap),
|
||||
reactiveHealthIndicators.getIfAvailable(Collections::emptyMap));
|
||||
}
|
||||
|
||||
private Map<String, HealthIndicator> merge(
|
||||
Map<String, HealthIndicator> healthIndicators,
|
||||
Map<String, ReactiveHealthIndicator> reactiveHealthIndicators) {
|
||||
if (ObjectUtils.isEmpty(reactiveHealthIndicators)) {
|
||||
return healthIndicators;
|
||||
}
|
||||
Map<String, HealthIndicator> allIndicators = new LinkedHashMap<>(
|
||||
healthIndicators);
|
||||
reactiveHealthIndicators.forEach((beanName, indicator) -> allIndicators
|
||||
.computeIfAbsent(beanName, n -> adapt(indicator)));
|
||||
return allIndicators;
|
||||
}
|
||||
|
||||
private HealthIndicator adapt(ReactiveHealthIndicator healthIndicator) {
|
||||
return () -> healthIndicator.health().block();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnBean(Flyway.class)
|
||||
@ConditionalOnClass(Flyway.class)
|
||||
static class FlywayEndpointConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnEnabledEndpoint
|
||||
public FlywayEndpoint flywayEndpoint(Map<String, Flyway> flyways) {
|
||||
return new FlywayEndpoint(flyways);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnBean(SpringLiquibase.class)
|
||||
@ConditionalOnClass(SpringLiquibase.class)
|
||||
static class LiquibaseEndpointConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnEnabledEndpoint
|
||||
public LiquibaseEndpoint liquibaseEndpoint(
|
||||
Map<String, SpringLiquibase> liquibases) {
|
||||
return new LiquibaseEndpoint(liquibases);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(AbstractHandlerMethodMapping.class)
|
||||
protected static class RequestMappingEndpointConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnEnabledEndpoint
|
||||
public RequestMappingEndpoint requestMappingEndpoint() {
|
||||
RequestMappingEndpoint endpoint = new RequestMappingEndpoint();
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,42 +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 org.springframework.boot.actuate.autoconfigure.web.ManagementServerProperties;
|
||||
import org.springframework.boot.endpoint.EndpointPathResolver;
|
||||
|
||||
/**
|
||||
* {@link EndpointPathResolver} implementation for resolving actuator endpoint paths based
|
||||
* on the endpoint id and management.context-path.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class ManagementEndpointPathResolver implements EndpointPathResolver {
|
||||
|
||||
private final String contextPath;
|
||||
|
||||
public ManagementEndpointPathResolver(ManagementServerProperties properties) {
|
||||
this.contextPath = properties.getContextPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String resolvePath(String endpointId) {
|
||||
return this.contextPath + "/" + endpointId;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,136 +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 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.EndpointExposure;
|
||||
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.Assert;
|
||||
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 attributes = getEndpointAttributes(context, metadata);
|
||||
EndpointEnablement endpointEnablement = attributes
|
||||
.getEnablement(new EndpointEnablementProvider(context.getEnvironment()));
|
||||
return new ConditionOutcome(endpointEnablement.isEnabled(),
|
||||
ConditionMessage.forCondition(ConditionalOnEnabledEndpoint.class)
|
||||
.because(endpointEnablement.getReason()));
|
||||
}
|
||||
|
||||
private EndpointAttributes getEndpointAttributes(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
Assert.state(
|
||||
metadata instanceof MethodMetadata
|
||||
&& metadata.isAnnotated(Bean.class.getName()),
|
||||
"OnEnabledEndpointCondition may only be used on @Bean methods");
|
||||
return getEndpointAttributes(context, (MethodMetadata) metadata);
|
||||
}
|
||||
|
||||
private EndpointAttributes getEndpointAttributes(ConditionContext context,
|
||||
MethodMetadata methodMetadata) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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 exposure technologies are exposed
|
||||
EndpointExposure[] exposures = endpoint.exposure();
|
||||
return new EndpointAttributes(endpoint.id(), endpoint.enabledByDefault(),
|
||||
(exposures.length == 1 ? exposures[0] : null));
|
||||
}
|
||||
|
||||
private static class EndpointAttributes {
|
||||
|
||||
private final String id;
|
||||
|
||||
private final boolean enabled;
|
||||
|
||||
private final EndpointExposure exposure;
|
||||
|
||||
EndpointAttributes(String id, boolean enabled, EndpointExposure exposure) {
|
||||
if (!StringUtils.hasText(id)) {
|
||||
throw new IllegalStateException("Endpoint id could not be determined");
|
||||
}
|
||||
this.id = id;
|
||||
this.enabled = enabled;
|
||||
this.exposure = exposure;
|
||||
}
|
||||
|
||||
public EndpointEnablement getEnablement(EndpointEnablementProvider provider) {
|
||||
return provider.getEndpointEnablement(this.id, this.enabled, this.exposure);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,48 +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.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<String, CachingConfiguration> {
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -1,114 +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.infrastructure;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* Configuration properties for MVC endpoints' CORS support.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "management.endpoints.cors")
|
||||
public class CorsEndpointProperties {
|
||||
|
||||
/**
|
||||
* Comma-separated list of origins to allow. '*' allows all origins. When not set,
|
||||
* CORS support is disabled.
|
||||
*/
|
||||
private List<String> allowedOrigins = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Comma-separated list of methods to allow. '*' allows all methods. When not set,
|
||||
* defaults to GET.
|
||||
*/
|
||||
private List<String> allowedMethods = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Comma-separated list of headers to allow in a request. '*' allows all headers.
|
||||
*/
|
||||
private List<String> allowedHeaders = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Comma-separated list of headers to include in a response.
|
||||
*/
|
||||
private List<String> exposedHeaders = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Set whether credentials are supported. When not set, credentials are not supported.
|
||||
*/
|
||||
private Boolean allowCredentials;
|
||||
|
||||
/**
|
||||
* How long, in seconds, the response from a pre-flight request can be cached by
|
||||
* clients.
|
||||
*/
|
||||
private Long maxAge = 1800L;
|
||||
|
||||
public List<String> getAllowedOrigins() {
|
||||
return this.allowedOrigins;
|
||||
}
|
||||
|
||||
public void setAllowedOrigins(List<String> allowedOrigins) {
|
||||
this.allowedOrigins = allowedOrigins;
|
||||
}
|
||||
|
||||
public List<String> getAllowedMethods() {
|
||||
return this.allowedMethods;
|
||||
}
|
||||
|
||||
public void setAllowedMethods(List<String> allowedMethods) {
|
||||
this.allowedMethods = allowedMethods;
|
||||
}
|
||||
|
||||
public List<String> getAllowedHeaders() {
|
||||
return this.allowedHeaders;
|
||||
}
|
||||
|
||||
public void setAllowedHeaders(List<String> allowedHeaders) {
|
||||
this.allowedHeaders = allowedHeaders;
|
||||
}
|
||||
|
||||
public List<String> getExposedHeaders() {
|
||||
return this.exposedHeaders;
|
||||
}
|
||||
|
||||
public void setExposedHeaders(List<String> exposedHeaders) {
|
||||
this.exposedHeaders = exposedHeaders;
|
||||
}
|
||||
|
||||
public Boolean getAllowCredentials() {
|
||||
return this.allowCredentials;
|
||||
}
|
||||
|
||||
public void setAllowCredentials(Boolean allowCredentials) {
|
||||
this.allowCredentials = allowCredentials;
|
||||
}
|
||||
|
||||
public Long getMaxAge() {
|
||||
return this.maxAge;
|
||||
}
|
||||
|
||||
public void setMaxAge(Long maxAge) {
|
||||
this.maxAge = maxAge;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,85 +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.infrastructure;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.management.MBeanServer;
|
||||
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.ObjectUtils;
|
||||
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 final JmxEndpointExporterProperties properties;
|
||||
|
||||
private final MBeanServer mBeanServer;
|
||||
|
||||
private final String contextId;
|
||||
|
||||
DefaultEndpointObjectNameFactory(JmxEndpointExporterProperties properties,
|
||||
MBeanServer mBeanServer, String contextId) {
|
||||
this.properties = properties;
|
||||
this.mBeanServer = mBeanServer;
|
||||
this.contextId = contextId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectName generate(EndpointMBean mBean) throws MalformedObjectNameException {
|
||||
String baseObjectName = this.properties.getDomain() + ":type=Endpoint" + ",name="
|
||||
+ StringUtils.capitalize(mBean.getEndpointId());
|
||||
StringBuilder builder = new StringBuilder(baseObjectName);
|
||||
if (this.mBeanServer != null && hasMBean(baseObjectName)) {
|
||||
builder.append(",context=").append(this.contextId);
|
||||
}
|
||||
if (this.properties.isUniqueNames()) {
|
||||
builder.append(",identity=").append(ObjectUtils.getIdentityHexString(mBean));
|
||||
}
|
||||
builder.append(getStaticNames());
|
||||
return ObjectNameManager.getInstance(builder.toString());
|
||||
}
|
||||
|
||||
private boolean hasMBean(String baseObjectName) throws MalformedObjectNameException {
|
||||
ObjectName query = new ObjectName(baseObjectName + ",*");
|
||||
return this.mBeanServer.queryNames(query, null).size() > 0;
|
||||
}
|
||||
|
||||
private String getStaticNames() {
|
||||
if (this.properties.getStaticNames().isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
for (Map.Entry<Object, Object> name : this.properties.getStaticNames()
|
||||
.entrySet()) {
|
||||
builder.append(",").append(name.getKey()).append("=").append(name.getValue());
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,149 +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.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.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.endpoint.ConversionServiceOperationParameterMapper;
|
||||
import org.springframework.boot.endpoint.EndpointExposure;
|
||||
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.ObjectUtils;
|
||||
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)
|
||||
@EnableConfigurationProperties(JmxEndpointExporterProperties.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, this::convertToDate);
|
||||
return new ConversionServiceOperationParameterMapper(conversionService);
|
||||
}
|
||||
|
||||
private Date convertToDate(String value) {
|
||||
if (StringUtils.hasLength(value)) {
|
||||
OffsetDateTime offsetDateTime = OffsetDateTime.parse(value,
|
||||
DateTimeFormatter.ISO_OFFSET_DATE_TIME);
|
||||
return new Date(offsetDateTime.toEpochSecond() * 1000);
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
@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(JmxEndpointExporterProperties properties,
|
||||
MBeanServer mBeanServer, JmxAnnotationEndpointDiscoverer endpointDiscoverer,
|
||||
ObjectProvider<ObjectMapper> objectMapper) {
|
||||
EndpointProvider<JmxEndpointOperation> endpointProvider = new EndpointProvider<>(
|
||||
this.applicationContext.getEnvironment(), endpointDiscoverer,
|
||||
EndpointExposure.JMX);
|
||||
EndpointMBeanRegistrar endpointMBeanRegistrar = new EndpointMBeanRegistrar(
|
||||
mBeanServer, new DefaultEndpointObjectNameFactory(properties, mBeanServer,
|
||||
ObjectUtils.getIdentityHexString(this.applicationContext)));
|
||||
return new JmxEndpointExporter(endpointProvider, endpointMBeanRegistrar,
|
||||
objectMapper.getIfAvailable(ObjectMapper::new));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnWebApplication
|
||||
static class WebInfrastructureConfiguration {
|
||||
|
||||
private final ApplicationContext applicationContext;
|
||||
|
||||
WebInfrastructureConfiguration(ApplicationContext applicationContext) {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public EndpointProvider<WebEndpointOperation> webEndpointProvider(
|
||||
OperationParameterMapper operationParameterMapper,
|
||||
CachingConfigurationFactory cachingConfigurationFactory) {
|
||||
return new EndpointProvider<>(this.applicationContext.getEnvironment(),
|
||||
webEndpointDiscoverer(operationParameterMapper,
|
||||
cachingConfigurationFactory),
|
||||
EndpointExposure.WEB);
|
||||
}
|
||||
|
||||
private WebAnnotationEndpointDiscoverer webEndpointDiscoverer(
|
||||
OperationParameterMapper operationParameterMapper,
|
||||
CachingConfigurationFactory cachingConfigurationFactory) {
|
||||
List<String> mediaTypes = Arrays.asList(
|
||||
ActuatorMediaTypes.APPLICATION_ACTUATOR_V2_JSON_VALUE,
|
||||
"application/json");
|
||||
return new WebAnnotationEndpointDiscoverer(this.applicationContext,
|
||||
operationParameterMapper, cachingConfigurationFactory, mediaTypes,
|
||||
mediaTypes);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,68 +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.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.EndpointExposure;
|
||||
import org.springframework.boot.endpoint.EndpointInfo;
|
||||
import org.springframework.boot.endpoint.Operation;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
/**
|
||||
* Provides the endpoints that are enabled according to an {@link EndpointDiscoverer} and
|
||||
* the current {@link Environment}.
|
||||
*
|
||||
* @param <T> the endpoint operation type
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public final class EndpointProvider<T extends Operation> {
|
||||
|
||||
private final EndpointDiscoverer<T> discoverer;
|
||||
|
||||
private final EndpointEnablementProvider endpointEnablementProvider;
|
||||
|
||||
private final EndpointExposure exposure;
|
||||
|
||||
/**
|
||||
* 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 exposure the exposure technology for the endpoint
|
||||
*/
|
||||
public EndpointProvider(Environment environment, EndpointDiscoverer<T> discoverer,
|
||||
EndpointExposure exposure) {
|
||||
this.discoverer = discoverer;
|
||||
this.endpointEnablementProvider = new EndpointEnablementProvider(environment);
|
||||
this.exposure = exposure;
|
||||
}
|
||||
|
||||
public Collection<EndpointInfo<T>> 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.exposure).isEnabled();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,133 +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.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<JmxEndpointOperation> endpointProvider;
|
||||
|
||||
private final EndpointMBeanRegistrar endpointMBeanRegistrar;
|
||||
|
||||
private final JmxEndpointMBeanFactory mBeanFactory;
|
||||
|
||||
private Collection<ObjectName> registeredObjectNames;
|
||||
|
||||
JmxEndpointExporter(EndpointProvider<JmxEndpointOperation> 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<ObjectName> registerEndpointMBeans() {
|
||||
List<ObjectName> objectNames = new ArrayList<>();
|
||||
Collection<EndpointMBean> mBeans = this.mBeanFactory
|
||||
.createMBeans(this.endpointProvider.getEndpoints());
|
||||
for (EndpointMBean mBean : mBeans) {
|
||||
objectNames.add(this.endpointMBeanRegistrar.registerEndpointMBean(mBean));
|
||||
}
|
||||
return objectNames;
|
||||
}
|
||||
|
||||
private void unregisterEndpointMBeans(Collection<ObjectName> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.autoconfigure.endpoint.infrastructure;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Configuration properties for JMX export of endpoints.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@ConfigurationProperties("management.endpoints.jmx")
|
||||
public class JmxEndpointExporterProperties {
|
||||
|
||||
/**
|
||||
* Endpoints JMX domain name. Fallback to 'spring.jmx.default-domain' if set.
|
||||
*/
|
||||
private String domain = "org.springframework.boot";
|
||||
|
||||
/**
|
||||
* Ensure that ObjectNames are modified in case of conflict.
|
||||
*/
|
||||
private boolean uniqueNames = false;
|
||||
|
||||
/**
|
||||
* Additional static properties to append to all ObjectNames of MBeans representing
|
||||
* Endpoints.
|
||||
*/
|
||||
private final Properties staticNames = new Properties();
|
||||
|
||||
public JmxEndpointExporterProperties(Environment environment) {
|
||||
String defaultDomain = environment.getProperty("spring.jmx.default-domain");
|
||||
if (StringUtils.hasText(defaultDomain)) {
|
||||
this.domain = defaultDomain;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,89 +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.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 <T> the type of web server factory to customize
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
abstract class ManagementWebServerFactoryCustomizer<T extends ConfigurableWebServerFactory>
|
||||
implements WebServerFactoryCustomizer<T>, Ordered {
|
||||
|
||||
private final ListableBeanFactory beanFactory;
|
||||
|
||||
private final Class<? extends WebServerFactoryCustomizer<T>> customizerClass;
|
||||
|
||||
protected ManagementWebServerFactoryCustomizer(ListableBeanFactory beanFactory,
|
||||
Class<? extends WebServerFactoryCustomizer<T>> 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<T> 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.<ErrorPage>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()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,63 +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.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<ConfigurableReactiveWebServerFactory> {
|
||||
|
||||
ManagementReactiveWebServerFactoryCustomizer(ListableBeanFactory beanFactory) {
|
||||
super(beanFactory, DefaultReactiveWebServerCustomizer.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,85 +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.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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.autoconfigure.endpoint.infrastructure;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
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.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.ManagementErrorEndpoint;
|
||||
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.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.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.core.Ordered;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
import org.springframework.web.servlet.HandlerAdapter;
|
||||
import org.springframework.web.servlet.HandlerExceptionResolver;
|
||||
import org.springframework.web.servlet.HandlerExecutionChain;
|
||||
import org.springframework.web.servlet.HandlerMapping;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@Configuration
|
||||
@ManagementContextConfiguration(ManagementContextType.CHILD)
|
||||
@ConditionalOnWebApplication(type = Type.SERVLET)
|
||||
class ServletEndpointChildManagementContextConfiguration {
|
||||
|
||||
@Bean
|
||||
public ManagementServletWebServerFactoryCustomization serverCustomization(
|
||||
ListableBeanFactory beanFactory) {
|
||||
return new ManagementServletWebServerFactoryCustomization(beanFactory);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public UndertowAccessLogCustomizer undertowAccessLogCustomizer() {
|
||||
return new UndertowAccessLogCustomizer();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnClass(name = "org.apache.catalina.valves.AccessLogValve")
|
||||
public TomcatAccessLogCustomizer tomcatAccessLogCustomizer() {
|
||||
return new TomcatAccessLogCustomizer();
|
||||
}
|
||||
|
||||
@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
|
||||
@ConditionalOnClass(ResourceConfig.class)
|
||||
@ConditionalOnMissingClass("org.springframework.web.servlet.DispatcherServlet")
|
||||
static class JerseyEndpointChildContextConfiguration {
|
||||
|
||||
private final List<ResourceConfigCustomizer> resourceConfigCustomizers;
|
||||
|
||||
JerseyEndpointChildContextConfiguration(
|
||||
List<ResourceConfigCustomizer> resourceConfigCustomizers) {
|
||||
this.resourceConfigCustomizers = resourceConfigCustomizers;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ServletRegistrationBean<ServletContainer> jerseyServletRegistration() {
|
||||
ServletRegistrationBean<ServletContainer> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass({ EnableWebSecurity.class, Filter.class })
|
||||
@ConditionalOnBean(name = "springSecurityFilterChain", search = SearchStrategy.ANCESTORS)
|
||||
static class EndpointWebMvcChildContextSecurityConfiguration {
|
||||
|
||||
@Bean
|
||||
public Filter springSecurityFilterChain(HierarchicalBeanFactory beanFactory) {
|
||||
BeanFactory parent = beanFactory.getParentBeanFactory();
|
||||
return parent.getBean("springSecurityFilterChain", Filter.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class ManagementServletWebServerFactoryCustomization extends
|
||||
ManagementWebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
|
||||
|
||||
ManagementServletWebServerFactoryCustomization(ListableBeanFactory beanFactory) {
|
||||
super(beanFactory, DefaultServletWebServerFactoryCustomizer.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void customize(ConfigurableServletWebServerFactory webServerFactory,
|
||||
ManagementServerProperties managementServerProperties,
|
||||
ServerProperties serverProperties) {
|
||||
super.customize(webServerFactory, managementServerProperties,
|
||||
serverProperties);
|
||||
webServerFactory.setContextPath("");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class CompositeHandlerMapping implements HandlerMapping {
|
||||
|
||||
@Autowired
|
||||
private ListableBeanFactory beanFactory;
|
||||
|
||||
private List<HandlerMapping> mappings;
|
||||
|
||||
@Override
|
||||
public HandlerExecutionChain getHandler(HttpServletRequest request)
|
||||
throws Exception {
|
||||
if (this.mappings == null) {
|
||||
this.mappings = extractMappings();
|
||||
}
|
||||
for (HandlerMapping mapping : this.mappings) {
|
||||
HandlerExecutionChain handler = mapping.getHandler(request);
|
||||
if (handler != null) {
|
||||
return handler;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<HandlerMapping> extractMappings() {
|
||||
List<HandlerMapping> list = new ArrayList<>();
|
||||
list.addAll(this.beanFactory.getBeansOfType(HandlerMapping.class).values());
|
||||
list.remove(this);
|
||||
AnnotationAwareOrderComparator.sort(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class CompositeHandlerAdapter implements HandlerAdapter {
|
||||
|
||||
@Autowired
|
||||
private ListableBeanFactory beanFactory;
|
||||
|
||||
private List<HandlerAdapter> adapters;
|
||||
|
||||
private List<HandlerAdapter> extractAdapters() {
|
||||
List<HandlerAdapter> list = new ArrayList<>();
|
||||
list.addAll(this.beanFactory.getBeansOfType(HandlerAdapter.class).values());
|
||||
list.remove(this);
|
||||
AnnotationAwareOrderComparator.sort(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(Object handler) {
|
||||
if (this.adapters == null) {
|
||||
this.adapters = extractAdapters();
|
||||
}
|
||||
for (HandlerAdapter mapping : this.adapters) {
|
||||
if (mapping.supports(handler)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelAndView handle(HttpServletRequest request,
|
||||
HttpServletResponse response, Object handler) throws Exception {
|
||||
if (this.adapters == null) {
|
||||
this.adapters = extractAdapters();
|
||||
}
|
||||
for (HandlerAdapter mapping : this.adapters) {
|
||||
if (mapping.supports(handler)) {
|
||||
return mapping.handle(request, response, handler);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLastModified(HttpServletRequest request, Object handler) {
|
||||
if (this.adapters == null) {
|
||||
this.adapters = extractAdapters();
|
||||
}
|
||||
for (HandlerAdapter mapping : this.adapters) {
|
||||
if (mapping.supports(handler)) {
|
||||
return mapping.getLastModified(request, handler);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class CompositeHandlerExceptionResolver implements HandlerExceptionResolver {
|
||||
|
||||
@Autowired
|
||||
private ListableBeanFactory beanFactory;
|
||||
|
||||
private List<HandlerExceptionResolver> resolvers;
|
||||
|
||||
private List<HandlerExceptionResolver> extractResolvers() {
|
||||
List<HandlerExceptionResolver> list = new ArrayList<>();
|
||||
list.addAll(this.beanFactory.getBeansOfType(HandlerExceptionResolver.class)
|
||||
.values());
|
||||
list.remove(this);
|
||||
AnnotationAwareOrderComparator.sort(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelAndView resolveException(HttpServletRequest request,
|
||||
HttpServletResponse response, Object handler, Exception ex) {
|
||||
if (this.resolvers == null) {
|
||||
this.resolvers = extractResolvers();
|
||||
}
|
||||
for (HandlerExceptionResolver mapping : this.resolvers) {
|
||||
ModelAndView mav = mapping.resolveException(request, response, handler,
|
||||
ex);
|
||||
if (mav != null) {
|
||||
return mav;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static abstract class AccessLogCustomizer implements Ordered {
|
||||
|
||||
protected String customizePrefix(String prefix) {
|
||||
return "management_" + prefix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class TomcatAccessLogCustomizer extends AccessLogCustomizer
|
||||
implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
|
||||
|
||||
@Override
|
||||
public void customize(TomcatServletWebServerFactory serverFactory) {
|
||||
AccessLogValve accessLogValve = findAccessLogValve(serverFactory);
|
||||
if (accessLogValve == null) {
|
||||
return;
|
||||
}
|
||||
accessLogValve.setPrefix(customizePrefix(accessLogValve.getPrefix()));
|
||||
}
|
||||
|
||||
private AccessLogValve findAccessLogValve(
|
||||
TomcatServletWebServerFactory serverFactory) {
|
||||
for (Valve engineValve : serverFactory.getEngineValves()) {
|
||||
if (engineValve instanceof AccessLogValve) {
|
||||
return (AccessLogValve) engineValve;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class UndertowAccessLogCustomizer extends AccessLogCustomizer
|
||||
implements WebServerFactoryCustomizer<UndertowServletWebServerFactory> {
|
||||
|
||||
@Override
|
||||
public void customize(UndertowServletWebServerFactory serverFactory) {
|
||||
serverFactory.setAccessLogPrefix(
|
||||
customizePrefix(serverFactory.getAccessLogPrefix()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,148 +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.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.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.EndpointMapping;
|
||||
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({ CorsEndpointProperties.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<WebEndpointOperation> provider,
|
||||
ManagementServerProperties managementServerProperties) {
|
||||
return (resourceConfig) -> resourceConfig.registerResources(new HashSet<>(
|
||||
new JerseyEndpointResourceFactory().createEndpointResources(
|
||||
new EndpointMapping(
|
||||
managementServerProperties.getContextPath()),
|
||||
provider.getEndpoints())));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnWebApplication(type = Type.SERVLET)
|
||||
@ConditionalOnClass(DispatcherServlet.class)
|
||||
@ConditionalOnBean(DispatcherServlet.class)
|
||||
static class MvcWebEndpointConfiguration {
|
||||
|
||||
private final List<WebEndpointHandlerMappingCustomizer> mappingCustomizers;
|
||||
|
||||
MvcWebEndpointConfiguration(
|
||||
ObjectProvider<List<WebEndpointHandlerMappingCustomizer>> mappingCustomizers) {
|
||||
this.mappingCustomizers = mappingCustomizers
|
||||
.getIfUnique(Collections::emptyList);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public WebEndpointServletHandlerMapping webEndpointServletHandlerMapping(
|
||||
EndpointProvider<WebEndpointOperation> provider,
|
||||
CorsEndpointProperties corsProperties,
|
||||
ManagementServerProperties managementServerProperties) {
|
||||
WebEndpointServletHandlerMapping handlerMapping = new WebEndpointServletHandlerMapping(
|
||||
new EndpointMapping(managementServerProperties.getContextPath()),
|
||||
provider.getEndpoints(), getCorsConfiguration(corsProperties));
|
||||
for (WebEndpointHandlerMappingCustomizer customizer : this.mappingCustomizers) {
|
||||
customizer.customize(handlerMapping);
|
||||
}
|
||||
return handlerMapping;
|
||||
}
|
||||
|
||||
private CorsConfiguration getCorsConfiguration(
|
||||
CorsEndpointProperties 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<WebEndpointOperation> provider,
|
||||
ManagementServerProperties managementServerProperties) {
|
||||
return new WebEndpointReactiveHandlerMapping(
|
||||
new EndpointMapping(managementServerProperties.getContextPath()),
|
||||
provider.getEndpoints());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,21 +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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
* Auto-configuration} for the Actuator's endpoint infrastructure.
|
||||
*/
|
||||
package org.springframework.boot.actuate.autoconfigure.endpoint.infrastructure;
|
||||
@@ -1,50 +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.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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,21 +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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
* Auto-configuration} for the Actuator's JMX endpoints.
|
||||
*/
|
||||
package org.springframework.boot.actuate.autoconfigure.endpoint.jmx;
|
||||
@@ -1,57 +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.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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,175 +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.support;
|
||||
|
||||
import org.springframework.boot.endpoint.EndpointExposure;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* 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 exposure the requested {@link EndpointExposure}
|
||||
* @return the {@link EndpointEnablement} of that endpoint for the specified
|
||||
* {@link EndpointExposure}
|
||||
*/
|
||||
public EndpointEnablement getEndpointEnablement(String endpointId,
|
||||
boolean enabledByDefault, EndpointExposure exposure) {
|
||||
Assert.hasText(endpointId, "Endpoint id must have a value");
|
||||
Assert.isTrue(!endpointId.equals("default"),
|
||||
"Endpoint id 'default' is a reserved "
|
||||
+ "value and cannot be used by an endpoint");
|
||||
EndpointEnablement result = findEnablement(endpointId, exposure);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
result = findEnablement(getKey(endpointId, "enabled"));
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
// All endpoints specific attributes have been looked at. Checking default value
|
||||
// for the endpoint
|
||||
if (!enabledByDefault) {
|
||||
return getDefaultEndpointEnablement(endpointId, false, exposure);
|
||||
}
|
||||
return getGlobalEndpointEnablement(endpointId, enabledByDefault, exposure);
|
||||
}
|
||||
|
||||
private EndpointEnablement findEnablement(String endpointId,
|
||||
EndpointExposure exposure) {
|
||||
if (exposure != null) {
|
||||
return findEnablement(getKey(endpointId, exposure));
|
||||
}
|
||||
return findEnablementForAnyExposureTechnology(endpointId);
|
||||
}
|
||||
|
||||
private EndpointEnablement getGlobalEndpointEnablement(String endpointId,
|
||||
boolean enabledByDefault, EndpointExposure exposure) {
|
||||
EndpointEnablement result = findGlobalEndpointEnablement(exposure);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
result = findEnablement(getKey("default", "enabled"));
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
return getDefaultEndpointEnablement(endpointId, enabledByDefault, exposure);
|
||||
}
|
||||
|
||||
private EndpointEnablement findGlobalEndpointEnablement(EndpointExposure exposure) {
|
||||
if (exposure != null) {
|
||||
EndpointEnablement result = findEnablement(getKey("default", exposure));
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
if (!exposure.isEnabledByDefault()) {
|
||||
return getDefaultEndpointEnablement("default", false, exposure);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return findEnablementForAnyExposureTechnology("default");
|
||||
}
|
||||
|
||||
private EndpointEnablement findEnablementForAnyExposureTechnology(String endpointId) {
|
||||
for (EndpointExposure candidate : EndpointExposure.values()) {
|
||||
EndpointEnablement result = findEnablementForExposureTechnology(endpointId,
|
||||
candidate);
|
||||
if (result != null && result.isEnabled()) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private EndpointEnablement findEnablementForExposureTechnology(String endpointId,
|
||||
EndpointExposure exposure) {
|
||||
String endpointTypeKey = getKey(endpointId, exposure);
|
||||
return findEnablement(endpointTypeKey);
|
||||
}
|
||||
|
||||
private EndpointEnablement getDefaultEndpointEnablement(String endpointId,
|
||||
boolean enabledByDefault, EndpointExposure exposure) {
|
||||
return new EndpointEnablement(enabledByDefault,
|
||||
createDefaultEnablementMessage(endpointId, enabledByDefault, exposure));
|
||||
}
|
||||
|
||||
private String createDefaultEnablementMessage(String endpointId,
|
||||
boolean enabledByDefault, EndpointExposure exposure) {
|
||||
StringBuilder message = new StringBuilder();
|
||||
message.append(String.format("endpoint '%s' ", endpointId));
|
||||
if (exposure != null) {
|
||||
message.append(String.format("(%s) ", exposure.name().toLowerCase()));
|
||||
}
|
||||
message.append(String.format("is %s by default",
|
||||
(enabledByDefault ? "enabled" : "disabled")));
|
||||
return message.toString();
|
||||
}
|
||||
|
||||
private String getKey(String endpointId, EndpointExposure exposure) {
|
||||
return getKey(endpointId, exposure.name().toLowerCase() + ".enabled");
|
||||
}
|
||||
|
||||
private String getKey(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 findEnablement(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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,20 +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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Support classes for the Actuator's endpoint auto-configuration.
|
||||
*/
|
||||
package org.springframework.boot.actuate.autoconfigure.endpoint.support;
|
||||
@@ -1,128 +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.web;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.ConditionalOnEnabledEndpoint;
|
||||
import org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorProperties;
|
||||
import org.springframework.boot.actuate.endpoint.HealthEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.StatusEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.web.HealthReactiveWebEndpointExtension;
|
||||
import org.springframework.boot.actuate.endpoint.web.HealthWebEndpointExtension;
|
||||
import org.springframework.boot.actuate.endpoint.web.StatusReactiveWebEndpointExtension;
|
||||
import org.springframework.boot.actuate.endpoint.web.StatusWebEndpointExtension;
|
||||
import org.springframework.boot.actuate.health.CompositeReactiveHealthIndicatorFactory;
|
||||
import org.springframework.boot.actuate.health.HealthAggregator;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.HealthStatusHttpMapper;
|
||||
import org.springframework.boot.actuate.health.OrderedHealthAggregator;
|
||||
import org.springframework.boot.actuate.health.ReactiveHealthIndicator;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
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.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Configuration for web-specific health endpoints .
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(HealthIndicatorProperties.class)
|
||||
public class HealthWebEndpointConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public HealthStatusHttpMapper createHealthStatusHttpMapper(
|
||||
HealthIndicatorProperties healthIndicatorProperties) {
|
||||
HealthStatusHttpMapper statusHttpMapper = new HealthStatusHttpMapper();
|
||||
if (healthIndicatorProperties.getHttpMapping() != null) {
|
||||
statusHttpMapper.addStatusMapping(healthIndicatorProperties.getHttpMapping());
|
||||
}
|
||||
return statusHttpMapper;
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnWebApplication(type = Type.REACTIVE)
|
||||
static class ReactiveWebHealthConfiguration {
|
||||
|
||||
private final ReactiveHealthIndicator reactiveHealthIndicator;
|
||||
|
||||
ReactiveWebHealthConfiguration(ObjectProvider<HealthAggregator> healthAggregator,
|
||||
ObjectProvider<Map<String, ReactiveHealthIndicator>> reactiveHealthIndicators,
|
||||
ObjectProvider<Map<String, HealthIndicator>> healthIndicators) {
|
||||
this.reactiveHealthIndicator = new CompositeReactiveHealthIndicatorFactory()
|
||||
.createReactiveHealthIndicator(
|
||||
healthAggregator.getIfAvailable(OrderedHealthAggregator::new),
|
||||
reactiveHealthIndicators
|
||||
.getIfAvailable(Collections::emptyMap),
|
||||
healthIndicators.getIfAvailable(Collections::emptyMap));
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnEnabledEndpoint
|
||||
@ConditionalOnBean(HealthEndpoint.class)
|
||||
public HealthReactiveWebEndpointExtension healthWebEndpointExtension(
|
||||
HealthStatusHttpMapper healthStatusHttpMapper) {
|
||||
return new HealthReactiveWebEndpointExtension(this.reactiveHealthIndicator,
|
||||
healthStatusHttpMapper);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnEnabledEndpoint
|
||||
@ConditionalOnBean(StatusEndpoint.class)
|
||||
public StatusReactiveWebEndpointExtension statusWebEndpointExtension(
|
||||
HealthStatusHttpMapper healthStatusHttpMapper) {
|
||||
return new StatusReactiveWebEndpointExtension(this.reactiveHealthIndicator,
|
||||
healthStatusHttpMapper);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnWebApplication(type = Type.SERVLET)
|
||||
static class ServletWebHealthConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnEnabledEndpoint
|
||||
@ConditionalOnBean(HealthEndpoint.class)
|
||||
public HealthWebEndpointExtension healthWebEndpointExtension(
|
||||
HealthEndpoint delegate, HealthStatusHttpMapper healthStatusHttpMapper) {
|
||||
return new HealthWebEndpointExtension(delegate, healthStatusHttpMapper);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnEnabledEndpoint
|
||||
@ConditionalOnBean(StatusEndpoint.class)
|
||||
public StatusWebEndpointExtension statusWebEndpointExtension(
|
||||
StatusEndpoint delegate, HealthStatusHttpMapper healthStatusHttpMapper) {
|
||||
return new StatusWebEndpointExtension(delegate, healthStatusHttpMapper);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.autoconfigure.endpoint.web;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.ManagementContextConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.ConditionalOnEnabledEndpoint;
|
||||
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.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Import;
|
||||
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
|
||||
@Import(HealthWebEndpointConfiguration.class)
|
||||
public class WebEndpointManagementContextConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnEnabledEndpoint
|
||||
public HeapDumpWebEndpoint heapDumpWebEndpoint() {
|
||||
return new HeapDumpWebEndpoint();
|
||||
}
|
||||
|
||||
@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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,21 +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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
* Auto-configuration} for the Actuator's web endpoints.
|
||||
*/
|
||||
package org.springframework.boot.actuate.autoconfigure.endpoint.web;
|
||||
@@ -1,70 +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.health;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.actuate.health.CompositeHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.HealthAggregator;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.core.ResolvableType;
|
||||
|
||||
/**
|
||||
* Base class for configurations that can combine source beans using a
|
||||
* {@link CompositeHealthIndicator}.
|
||||
*
|
||||
* @param <H> the health indicator type
|
||||
* @param <S> the bean source type
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public abstract class CompositeHealthIndicatorConfiguration<H extends HealthIndicator, S> {
|
||||
|
||||
@Autowired
|
||||
private HealthAggregator healthAggregator;
|
||||
|
||||
protected HealthIndicator createHealthIndicator(Map<String, S> beans) {
|
||||
if (beans.size() == 1) {
|
||||
return createHealthIndicator(beans.values().iterator().next());
|
||||
}
|
||||
CompositeHealthIndicator composite = new CompositeHealthIndicator(
|
||||
this.healthAggregator);
|
||||
for (Map.Entry<String, S> entry : beans.entrySet()) {
|
||||
composite.addHealthIndicator(entry.getKey(),
|
||||
createHealthIndicator(entry.getValue()));
|
||||
}
|
||||
return composite;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected H createHealthIndicator(S source) {
|
||||
Class<?>[] generics = ResolvableType
|
||||
.forClass(CompositeHealthIndicatorConfiguration.class, getClass())
|
||||
.resolveGenerics();
|
||||
Class<H> indicatorClass = (Class<H>) generics[0];
|
||||
Class<S> sourceClass = (Class<S>) generics[1];
|
||||
try {
|
||||
return indicatorClass.getConstructor(sourceClass).newInstance(source);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException("Unable to create indicator " + indicatorClass
|
||||
+ " for source " + sourceClass, ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,69 +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.health;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.actuate.health.CompositeReactiveHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.HealthAggregator;
|
||||
import org.springframework.boot.actuate.health.ReactiveHealthIndicator;
|
||||
import org.springframework.core.ResolvableType;
|
||||
|
||||
/**
|
||||
* Reactive variant of {@link CompositeHealthIndicatorConfiguration}.
|
||||
*
|
||||
* @param <H> the health indicator type
|
||||
* @param <S> the bean source type
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class CompositeReactiveHealthIndicatorConfiguration<H extends ReactiveHealthIndicator, S> {
|
||||
|
||||
@Autowired
|
||||
private HealthAggregator healthAggregator;
|
||||
|
||||
protected ReactiveHealthIndicator createHealthIndicator(Map<String, S> beans) {
|
||||
if (beans.size() == 1) {
|
||||
return createHealthIndicator(beans.values().iterator().next());
|
||||
}
|
||||
CompositeReactiveHealthIndicator composite = new CompositeReactiveHealthIndicator(
|
||||
this.healthAggregator);
|
||||
for (Map.Entry<String, S> entry : beans.entrySet()) {
|
||||
composite.addHealthIndicator(entry.getKey(),
|
||||
createHealthIndicator(entry.getValue()));
|
||||
}
|
||||
return composite;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected H createHealthIndicator(S source) {
|
||||
Class<?>[] generics = ResolvableType
|
||||
.forClass(CompositeReactiveHealthIndicatorConfiguration.class, getClass())
|
||||
.resolveGenerics();
|
||||
Class<H> indicatorClass = (Class<H>) generics[0];
|
||||
Class<S> sourceClass = (Class<S>) generics[1];
|
||||
try {
|
||||
return indicatorClass.getConstructor(sourceClass).newInstance(source);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException("Unable to create indicator " + indicatorClass
|
||||
+ " for source " + sourceClass, ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.autoconfigure.health;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import io.searchbox.client.JestClient;
|
||||
import org.elasticsearch.client.Client;
|
||||
|
||||
import org.springframework.boot.actuate.health.ElasticsearchHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.ElasticsearchHealthIndicatorProperties;
|
||||
import org.springframework.boot.actuate.health.ElasticsearchJestHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Actual Elasticsearch health indicator configurations imported by
|
||||
* {@link HealthIndicatorAutoConfiguration}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class ElasticsearchHealthIndicatorConfiguration {
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnBean(Client.class)
|
||||
@ConditionalOnEnabledHealthIndicator("elasticsearch")
|
||||
@EnableConfigurationProperties(ElasticsearchHealthIndicatorProperties.class)
|
||||
static class ElasticsearchClientHealthIndicatorConfiguration extends
|
||||
CompositeHealthIndicatorConfiguration<ElasticsearchHealthIndicator, Client> {
|
||||
|
||||
private final Map<String, Client> clients;
|
||||
|
||||
private final ElasticsearchHealthIndicatorProperties properties;
|
||||
|
||||
ElasticsearchClientHealthIndicatorConfiguration(Map<String, Client> clients,
|
||||
ElasticsearchHealthIndicatorProperties properties) {
|
||||
this.clients = clients;
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(name = "elasticsearchHealthIndicator")
|
||||
public HealthIndicator elasticsearchHealthIndicator() {
|
||||
return createHealthIndicator(this.clients);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ElasticsearchHealthIndicator createHealthIndicator(Client client) {
|
||||
return new ElasticsearchHealthIndicator(client, this.properties);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnBean(JestClient.class)
|
||||
@ConditionalOnEnabledHealthIndicator("elasticsearch")
|
||||
static class ElasticsearchJestHealthIndicatorConfiguration extends
|
||||
CompositeHealthIndicatorConfiguration<ElasticsearchJestHealthIndicator, JestClient> {
|
||||
|
||||
private final Map<String, JestClient> clients;
|
||||
|
||||
ElasticsearchJestHealthIndicatorConfiguration(Map<String, JestClient> clients) {
|
||||
this.clients = clients;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(name = "elasticsearchHealthIndicator")
|
||||
public HealthIndicator elasticsearchHealthIndicator() {
|
||||
return createHealthIndicator(this.clients);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ElasticsearchJestHealthIndicator createHealthIndicator(
|
||||
JestClient client) {
|
||||
return new ElasticsearchJestHealthIndicator(client);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.autoconfigure.health;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.health.HealthAggregator;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.OrderedHealthAggregator;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.data.ldap.LdapDataAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for {@link HealthIndicator}s.
|
||||
*
|
||||
* @author Christian Dupuis
|
||||
* @author Andy Wilkinson
|
||||
* @author Stephane Nicoll
|
||||
* @author Phillip Webb
|
||||
* @author Tommy Ludwig
|
||||
* @author Eddú Meléndez
|
||||
* @author Eric Spiegelberg
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@AutoConfigureBefore({ EndpointAutoConfiguration.class })
|
||||
@AutoConfigureAfter({ ActiveMQAutoConfiguration.class, ArtemisAutoConfiguration.class,
|
||||
CassandraAutoConfiguration.class, CassandraDataAutoConfiguration.class,
|
||||
CouchbaseDataAutoConfiguration.class, DataSourceAutoConfiguration.class,
|
||||
ElasticsearchAutoConfiguration.class, JestAutoConfiguration.class,
|
||||
LdapDataAutoConfiguration.class, MailSenderAutoConfiguration.class,
|
||||
MongoAutoConfiguration.class, MongoDataAutoConfiguration.class,
|
||||
Neo4jDataAutoConfiguration.class, RabbitAutoConfiguration.class,
|
||||
RedisAutoConfiguration.class, SolrAutoConfiguration.class })
|
||||
@EnableConfigurationProperties({ HealthIndicatorProperties.class })
|
||||
@Import({ ReactiveHealthIndicatorsConfiguration.class,
|
||||
HealthIndicatorsConfiguration.class })
|
||||
public class HealthIndicatorAutoConfiguration {
|
||||
|
||||
private final HealthIndicatorProperties properties;
|
||||
|
||||
public HealthIndicatorAutoConfiguration(HealthIndicatorProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(HealthAggregator.class)
|
||||
public OrderedHealthAggregator healthAggregator() {
|
||||
OrderedHealthAggregator healthAggregator = new OrderedHealthAggregator();
|
||||
if (this.properties.getOrder() != null) {
|
||||
healthAggregator.setStatusOrder(this.properties.getOrder());
|
||||
}
|
||||
return healthAggregator;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,59 +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.health;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* Configuration properties for some health properties.
|
||||
*
|
||||
* @author Christian Dupuis
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "management.health.status")
|
||||
public class HealthIndicatorProperties {
|
||||
|
||||
/**
|
||||
* Comma-separated list of health statuses in order of severity.
|
||||
*/
|
||||
private List<String> order = null;
|
||||
|
||||
/**
|
||||
* Mapping of health statuses to HttpStatus codes. By default, registered health
|
||||
* statuses map to sensible defaults (i.e. UP maps to 200).
|
||||
*/
|
||||
private final Map<String, Integer> httpMapping = new HashMap<>();
|
||||
|
||||
public List<String> getOrder() {
|
||||
return this.order;
|
||||
}
|
||||
|
||||
public void setOrder(List<String> statusOrder) {
|
||||
if (statusOrder != null && !statusOrder.isEmpty()) {
|
||||
this.order = statusOrder;
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, Integer> getHttpMapping() {
|
||||
return this.httpMapping;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,381 +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.health;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.jms.ConnectionFactory;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import com.datastax.driver.core.Cluster;
|
||||
import org.apache.solr.client.solrj.SolrClient;
|
||||
import org.neo4j.ogm.session.SessionFactory;
|
||||
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.actuate.health.ApplicationHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.CassandraHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.CouchbaseHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.DataSourceHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.DiskSpaceHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.DiskSpaceHealthIndicatorProperties;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.JmsHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.LdapHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.MailHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.MongoHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Neo4jHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.RabbitHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.RedisHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.SolrHealthIndicator;
|
||||
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.jdbc.metadata.DataSourcePoolMetadata;
|
||||
import org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadataProvider;
|
||||
import org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadataProviders;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.cassandra.core.CassandraOperations;
|
||||
import org.springframework.data.couchbase.core.CouchbaseOperations;
|
||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
|
||||
import org.springframework.ldap.core.LdapOperations;
|
||||
import org.springframework.mail.javamail.JavaMailSenderImpl;
|
||||
|
||||
/**
|
||||
* Configuration for available {@link HealthIndicator health indicators}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@Import({
|
||||
ElasticsearchHealthIndicatorConfiguration.ElasticsearchClientHealthIndicatorConfiguration.class,
|
||||
ElasticsearchHealthIndicatorConfiguration.ElasticsearchJestHealthIndicatorConfiguration.class })
|
||||
public class HealthIndicatorsConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(HealthIndicator.class)
|
||||
public ApplicationHealthIndicator applicationHealthIndicator() {
|
||||
return new ApplicationHealthIndicator();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass({ CassandraOperations.class, Cluster.class })
|
||||
@ConditionalOnBean(CassandraOperations.class)
|
||||
@ConditionalOnEnabledHealthIndicator("cassandra")
|
||||
public static class CassandraHealthIndicatorConfiguration extends
|
||||
CompositeHealthIndicatorConfiguration<CassandraHealthIndicator, CassandraOperations> {
|
||||
|
||||
private final Map<String, CassandraOperations> cassandraOperations;
|
||||
|
||||
public CassandraHealthIndicatorConfiguration(
|
||||
Map<String, CassandraOperations> cassandraOperations) {
|
||||
this.cassandraOperations = cassandraOperations;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(name = "cassandraHealthIndicator")
|
||||
public HealthIndicator cassandraHealthIndicator() {
|
||||
return createHealthIndicator(this.cassandraOperations);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass({ CouchbaseOperations.class, Bucket.class })
|
||||
@ConditionalOnBean(CouchbaseOperations.class)
|
||||
@ConditionalOnEnabledHealthIndicator("couchbase")
|
||||
public static class CouchbaseHealthIndicatorConfiguration extends
|
||||
CompositeHealthIndicatorConfiguration<CouchbaseHealthIndicator, CouchbaseOperations> {
|
||||
|
||||
private final Map<String, CouchbaseOperations> couchbaseOperations;
|
||||
|
||||
public CouchbaseHealthIndicatorConfiguration(
|
||||
Map<String, CouchbaseOperations> couchbaseOperations) {
|
||||
this.couchbaseOperations = couchbaseOperations;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(name = "couchbaseHealthIndicator")
|
||||
public HealthIndicator couchbaseHealthIndicator() {
|
||||
return createHealthIndicator(this.couchbaseOperations);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass({ JdbcTemplate.class, AbstractRoutingDataSource.class })
|
||||
@ConditionalOnBean(DataSource.class)
|
||||
@ConditionalOnEnabledHealthIndicator("db")
|
||||
public static class DataSourcesHealthIndicatorConfiguration extends
|
||||
CompositeHealthIndicatorConfiguration<DataSourceHealthIndicator, DataSource>
|
||||
implements InitializingBean {
|
||||
|
||||
private final Map<String, DataSource> dataSources;
|
||||
|
||||
private final Collection<DataSourcePoolMetadataProvider> metadataProviders;
|
||||
|
||||
private DataSourcePoolMetadataProvider poolMetadataProvider;
|
||||
|
||||
public DataSourcesHealthIndicatorConfiguration(
|
||||
ObjectProvider<Map<String, DataSource>> dataSources,
|
||||
ObjectProvider<Collection<DataSourcePoolMetadataProvider>> metadataProviders) {
|
||||
this.dataSources = filterDataSources(dataSources.getIfAvailable());
|
||||
this.metadataProviders = metadataProviders.getIfAvailable();
|
||||
}
|
||||
|
||||
private Map<String, DataSource> filterDataSources(
|
||||
Map<String, DataSource> candidates) {
|
||||
if (candidates == null) {
|
||||
return null;
|
||||
}
|
||||
Map<String, DataSource> dataSources = new LinkedHashMap<>();
|
||||
for (Map.Entry<String, DataSource> entry : candidates.entrySet()) {
|
||||
if (!(entry.getValue() instanceof AbstractRoutingDataSource)) {
|
||||
dataSources.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
return dataSources;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
this.poolMetadataProvider = new DataSourcePoolMetadataProviders(
|
||||
this.metadataProviders);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(name = "dbHealthIndicator")
|
||||
public HealthIndicator dbHealthIndicator() {
|
||||
return createHealthIndicator(this.dataSources);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DataSourceHealthIndicator createHealthIndicator(DataSource source) {
|
||||
return new DataSourceHealthIndicator(source, getValidationQuery(source));
|
||||
}
|
||||
|
||||
private String getValidationQuery(DataSource source) {
|
||||
DataSourcePoolMetadata poolMetadata = this.poolMetadataProvider
|
||||
.getDataSourcePoolMetadata(source);
|
||||
return (poolMetadata == null ? null : poolMetadata.getValidationQuery());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(LdapOperations.class)
|
||||
@ConditionalOnBean(LdapOperations.class)
|
||||
@ConditionalOnEnabledHealthIndicator("ldap")
|
||||
public static class LdapHealthIndicatorConfiguration extends
|
||||
CompositeHealthIndicatorConfiguration<LdapHealthIndicator, LdapOperations> {
|
||||
|
||||
private final Map<String, LdapOperations> ldapOperations;
|
||||
|
||||
public LdapHealthIndicatorConfiguration(
|
||||
Map<String, LdapOperations> ldapOperations) {
|
||||
this.ldapOperations = ldapOperations;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(name = "ldapHealthIndicator")
|
||||
public HealthIndicator ldapHealthIndicator() {
|
||||
return createHealthIndicator(this.ldapOperations);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(MongoTemplate.class)
|
||||
@ConditionalOnBean(MongoTemplate.class)
|
||||
@ConditionalOnEnabledHealthIndicator("mongo")
|
||||
public static class MongoHealthIndicatorConfiguration extends
|
||||
CompositeHealthIndicatorConfiguration<MongoHealthIndicator, MongoTemplate> {
|
||||
|
||||
private final Map<String, MongoTemplate> mongoTemplates;
|
||||
|
||||
public MongoHealthIndicatorConfiguration(
|
||||
Map<String, MongoTemplate> mongoTemplates) {
|
||||
this.mongoTemplates = mongoTemplates;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(name = "mongoHealthIndicator")
|
||||
public HealthIndicator mongoHealthIndicator() {
|
||||
return createHealthIndicator(this.mongoTemplates);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(SessionFactory.class)
|
||||
@ConditionalOnBean(SessionFactory.class)
|
||||
@ConditionalOnEnabledHealthIndicator("neo4j")
|
||||
public static class Neo4jHealthIndicatorConfiguration extends
|
||||
CompositeHealthIndicatorConfiguration<Neo4jHealthIndicator, SessionFactory> {
|
||||
|
||||
private final Map<String, SessionFactory> sessionFactories;
|
||||
|
||||
public Neo4jHealthIndicatorConfiguration(
|
||||
Map<String, SessionFactory> sessionFactories) {
|
||||
this.sessionFactories = sessionFactories;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(name = "neo4jHealthIndicator")
|
||||
public HealthIndicator neo4jHealthIndicator() {
|
||||
return createHealthIndicator(this.sessionFactories);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(RedisConnectionFactory.class)
|
||||
@ConditionalOnBean(RedisConnectionFactory.class)
|
||||
@ConditionalOnEnabledHealthIndicator("redis")
|
||||
public static class RedisHealthIndicatorConfiguration extends
|
||||
CompositeHealthIndicatorConfiguration<RedisHealthIndicator, RedisConnectionFactory> {
|
||||
|
||||
private final Map<String, RedisConnectionFactory> redisConnectionFactories;
|
||||
|
||||
public RedisHealthIndicatorConfiguration(
|
||||
Map<String, RedisConnectionFactory> redisConnectionFactories) {
|
||||
this.redisConnectionFactories = redisConnectionFactories;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(name = "redisHealthIndicator")
|
||||
public HealthIndicator redisHealthIndicator() {
|
||||
return createHealthIndicator(this.redisConnectionFactories);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(RabbitTemplate.class)
|
||||
@ConditionalOnBean(RabbitTemplate.class)
|
||||
@ConditionalOnEnabledHealthIndicator("rabbit")
|
||||
public static class RabbitHealthIndicatorConfiguration extends
|
||||
CompositeHealthIndicatorConfiguration<RabbitHealthIndicator, RabbitTemplate> {
|
||||
|
||||
private final Map<String, RabbitTemplate> rabbitTemplates;
|
||||
|
||||
public RabbitHealthIndicatorConfiguration(
|
||||
Map<String, RabbitTemplate> rabbitTemplates) {
|
||||
this.rabbitTemplates = rabbitTemplates;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(name = "rabbitHealthIndicator")
|
||||
public HealthIndicator rabbitHealthIndicator() {
|
||||
return createHealthIndicator(this.rabbitTemplates);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(SolrClient.class)
|
||||
@ConditionalOnBean(SolrClient.class)
|
||||
@ConditionalOnEnabledHealthIndicator("solr")
|
||||
public static class SolrHealthIndicatorConfiguration extends
|
||||
CompositeHealthIndicatorConfiguration<SolrHealthIndicator, SolrClient> {
|
||||
|
||||
private final Map<String, SolrClient> solrClients;
|
||||
|
||||
public SolrHealthIndicatorConfiguration(Map<String, SolrClient> solrClients) {
|
||||
this.solrClients = solrClients;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(name = "solrHealthIndicator")
|
||||
public HealthIndicator solrHealthIndicator() {
|
||||
return createHealthIndicator(this.solrClients);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnEnabledHealthIndicator("diskspace")
|
||||
public static class DiskSpaceHealthIndicatorConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(name = "diskSpaceHealthIndicator")
|
||||
public DiskSpaceHealthIndicator diskSpaceHealthIndicator(
|
||||
DiskSpaceHealthIndicatorProperties properties) {
|
||||
return new DiskSpaceHealthIndicator(properties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DiskSpaceHealthIndicatorProperties diskSpaceHealthIndicatorProperties() {
|
||||
return new DiskSpaceHealthIndicatorProperties();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(JavaMailSenderImpl.class)
|
||||
@ConditionalOnBean(JavaMailSenderImpl.class)
|
||||
@ConditionalOnEnabledHealthIndicator("mail")
|
||||
public static class MailHealthIndicatorConfiguration extends
|
||||
CompositeHealthIndicatorConfiguration<MailHealthIndicator, JavaMailSenderImpl> {
|
||||
|
||||
private final Map<String, JavaMailSenderImpl> mailSenders;
|
||||
|
||||
public MailHealthIndicatorConfiguration(
|
||||
ObjectProvider<Map<String, JavaMailSenderImpl>> mailSenders) {
|
||||
this.mailSenders = mailSenders.getIfAvailable();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(name = "mailHealthIndicator")
|
||||
public HealthIndicator mailHealthIndicator() {
|
||||
return createHealthIndicator(this.mailSenders);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(ConnectionFactory.class)
|
||||
@ConditionalOnBean(ConnectionFactory.class)
|
||||
@ConditionalOnEnabledHealthIndicator("jms")
|
||||
public static class JmsHealthIndicatorConfiguration extends
|
||||
CompositeHealthIndicatorConfiguration<JmsHealthIndicator, ConnectionFactory> {
|
||||
|
||||
private final Map<String, ConnectionFactory> connectionFactories;
|
||||
|
||||
public JmsHealthIndicatorConfiguration(
|
||||
ObjectProvider<Map<String, ConnectionFactory>> connectionFactories) {
|
||||
this.connectionFactories = connectionFactories.getIfAvailable();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(name = "jmsHealthIndicator")
|
||||
public HealthIndicator jmsHealthIndicator() {
|
||||
return createHealthIndicator(this.connectionFactories);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,63 +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.health;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import org.springframework.boot.actuate.health.ReactiveHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.RedisReactiveHealthIndicator;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
|
||||
|
||||
/**
|
||||
* Configuration for available {@link ReactiveHealthIndicator reactive health indicators}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(Flux.class)
|
||||
public class ReactiveHealthIndicatorsConfiguration {
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnBean(ReactiveRedisConnectionFactory.class)
|
||||
@ConditionalOnEnabledHealthIndicator("redis")
|
||||
static class RedisHealthIndicatorConfiguration extends
|
||||
CompositeReactiveHealthIndicatorConfiguration<RedisReactiveHealthIndicator, ReactiveRedisConnectionFactory> {
|
||||
|
||||
private final Map<String, ReactiveRedisConnectionFactory> redisConnectionFactories;
|
||||
|
||||
RedisHealthIndicatorConfiguration(
|
||||
Map<String, ReactiveRedisConnectionFactory> redisConnectionFactories) {
|
||||
this.redisConnectionFactories = redisConnectionFactories;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(name = "redisHealthIndicator")
|
||||
public ReactiveHealthIndicator redisHealthIndicator() {
|
||||
return createHealthIndicator(this.redisConnectionFactories);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.autoconfigure.info;
|
||||
|
||||
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 a default info contributor is enabled.
|
||||
* Matches if the value of the {@code management.info.<name>.enabled} property is
|
||||
* {@code true}. Otherwise, matches if the value of the
|
||||
* {@code management.info.defaults.enabled} property is {@code true} or if it is not
|
||||
* configured.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@Documented
|
||||
@Conditional(OnEnabledInfoContributorCondition.class)
|
||||
public @interface ConditionalOnEnabledInfoContributor {
|
||||
|
||||
/**
|
||||
* The name of the info contributor.
|
||||
* @return the name of the info contributor
|
||||
*/
|
||||
String value();
|
||||
|
||||
}
|
||||
@@ -1,89 +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.info;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.info.BuildInfoContributor;
|
||||
import org.springframework.boot.actuate.info.EnvironmentInfoContributor;
|
||||
import org.springframework.boot.actuate.info.GitInfoContributor;
|
||||
import org.springframework.boot.actuate.info.InfoContributor;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
|
||||
import org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.info.BuildProperties;
|
||||
import org.springframework.boot.info.GitProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for standard
|
||||
* {@link InfoContributor}s.
|
||||
*
|
||||
* @author Meang Akira Tanaka
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@AutoConfigureAfter(ProjectInfoAutoConfiguration.class)
|
||||
@AutoConfigureBefore(EndpointAutoConfiguration.class)
|
||||
@EnableConfigurationProperties(InfoContributorProperties.class)
|
||||
public class InfoContributorAutoConfiguration {
|
||||
|
||||
/**
|
||||
* The default order for the core {@link InfoContributor} beans.
|
||||
*/
|
||||
public static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE + 10;
|
||||
|
||||
private final InfoContributorProperties properties;
|
||||
|
||||
public InfoContributorAutoConfiguration(InfoContributorProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnEnabledInfoContributor("env")
|
||||
@Order(DEFAULT_ORDER)
|
||||
public EnvironmentInfoContributor envInfoContributor(
|
||||
ConfigurableEnvironment environment) {
|
||||
return new EnvironmentInfoContributor(environment);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnEnabledInfoContributor("git")
|
||||
@ConditionalOnSingleCandidate(GitProperties.class)
|
||||
@ConditionalOnMissingBean
|
||||
@Order(DEFAULT_ORDER)
|
||||
public GitInfoContributor gitInfoContributor(GitProperties gitProperties) {
|
||||
return new GitInfoContributor(gitProperties, this.properties.getGit().getMode());
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnEnabledInfoContributor("build")
|
||||
@ConditionalOnSingleCandidate(BuildProperties.class)
|
||||
@Order(DEFAULT_ORDER)
|
||||
public InfoContributor buildInfoContributor(BuildProperties buildProperties) {
|
||||
return new BuildInfoContributor(buildProperties);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,54 +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.info;
|
||||
|
||||
import org.springframework.boot.actuate.info.GitInfoContributor;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* Configuration properties for core info contributors.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@ConfigurationProperties("management.info")
|
||||
public class InfoContributorProperties {
|
||||
|
||||
private final Git git = new Git();
|
||||
|
||||
public Git getGit() {
|
||||
return this.git;
|
||||
}
|
||||
|
||||
public static class Git {
|
||||
|
||||
/**
|
||||
* Mode to use to expose git information.
|
||||
*/
|
||||
private GitInfoContributor.Mode mode = GitInfoContributor.Mode.SIMPLE;
|
||||
|
||||
public GitInfoContributor.Mode getMode() {
|
||||
return this.mode;
|
||||
}
|
||||
|
||||
public void setMode(GitInfoContributor.Mode mode) {
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,81 +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.jolokia;
|
||||
|
||||
import org.jolokia.http.AgentServlet;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.ManagementContextConfiguration;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.ManagementServletContext;
|
||||
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.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.web.servlet.ServletRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.web.servlet.mvc.ServletWrappingController;
|
||||
|
||||
/**
|
||||
* {@link ManagementContextConfiguration} for embedding Jolokia, a JMX-HTTP bridge giving
|
||||
* an alternative to JSR-160 connectors.
|
||||
* <p>
|
||||
* This configuration will get automatically enabled as soon as the Jolokia
|
||||
* {@link AgentServlet} is on the classpath. To disable it set
|
||||
* {@code management.jolokia.enabled=false}.
|
||||
* <p>
|
||||
* Additional configuration parameters for Jolokia can be provided by specifying
|
||||
* {@code management.jolokia.config.*} properties. See the
|
||||
* <a href="http://jolokia.org">http://jolokia.org</a> web site for more information on
|
||||
* supported configuration parameters.
|
||||
*
|
||||
* @author Christian Dupuis
|
||||
* @author Dave Syer
|
||||
* @author Andy Wilkinson
|
||||
* @author Madhura Bhave
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@ManagementContextConfiguration
|
||||
@ConditionalOnWebApplication(type = Type.SERVLET)
|
||||
@ConditionalOnClass({ AgentServlet.class, ServletWrappingController.class })
|
||||
@ConditionalOnProperty(value = "management.jolokia.enabled", havingValue = "true")
|
||||
@EnableConfigurationProperties(JolokiaProperties.class)
|
||||
public class JolokiaManagementContextConfiguration {
|
||||
|
||||
private final ManagementServletContext managementServletContext;
|
||||
|
||||
private final JolokiaProperties properties;
|
||||
|
||||
public JolokiaManagementContextConfiguration(
|
||||
ManagementServletContext managementServletContext,
|
||||
JolokiaProperties properties) {
|
||||
this.managementServletContext = managementServletContext;
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ServletRegistrationBean<AgentServlet> jolokiaServlet() {
|
||||
String path = this.managementServletContext.getContextPath()
|
||||
+ this.properties.getPath();
|
||||
String urlMapping = (path.endsWith("/") ? path + "*" : path + "/*");
|
||||
ServletRegistrationBean<AgentServlet> registration = new ServletRegistrationBean<>(
|
||||
new AgentServlet(), urlMapping);
|
||||
registration.setInitParameters(this.properties.getConfig());
|
||||
return registration;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,71 +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.jolokia;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* Configuration properties for Jolokia.
|
||||
*
|
||||
* @author Christian Dupuis
|
||||
* @author Dave Syer
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "management.jolokia")
|
||||
public class JolokiaProperties {
|
||||
|
||||
/**
|
||||
* Enable Jolokia.
|
||||
*/
|
||||
private boolean enabled;
|
||||
|
||||
/**
|
||||
* Path at which Jolokia will be available.
|
||||
*/
|
||||
private String path = "/jolokia";
|
||||
|
||||
/**
|
||||
* Jolokia settings. These are traditionally set using servlet parameters. Refer to
|
||||
* the documentation of Jolokia for more details.
|
||||
*/
|
||||
private final Map<String, String> config = new HashMap<>();
|
||||
|
||||
public boolean isEnabled() {
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return this.path;
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public Map<String, String> getConfig() {
|
||||
return this.config;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,43 +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.metrics;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
|
||||
/**
|
||||
* Qualifier annotation for a metric reader that can be exported (to distinguish it from
|
||||
* others that might be installed by the user for other purposes).
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Qualifier
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE,
|
||||
ElementType.ANNOTATION_TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
public @interface ExportMetricReader {
|
||||
|
||||
}
|
||||
@@ -1,147 +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.metrics;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.actuate.endpoint.MetricsEndpointMetricReader;
|
||||
import org.springframework.boot.actuate.metrics.export.Exporter;
|
||||
import org.springframework.boot.actuate.metrics.export.MetricExportProperties;
|
||||
import org.springframework.boot.actuate.metrics.export.MetricExporters;
|
||||
import org.springframework.boot.actuate.metrics.reader.CompositeMetricReader;
|
||||
import org.springframework.boot.actuate.metrics.reader.MetricReader;
|
||||
import org.springframework.boot.actuate.metrics.statsd.StatsdMetricWriter;
|
||||
import org.springframework.boot.actuate.metrics.writer.GaugeWriter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.scheduling.annotation.SchedulingConfigurer;
|
||||
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for metrics export.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Simon Buettner
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@EnableScheduling
|
||||
@ConditionalOnProperty(value = "spring.metrics.export.enabled", matchIfMissing = true)
|
||||
@EnableConfigurationProperties
|
||||
public class MetricExportAutoConfiguration {
|
||||
|
||||
private final MetricsEndpointMetricReader endpointReader;
|
||||
|
||||
private final List<MetricReader> readers;
|
||||
|
||||
private final Map<String, GaugeWriter> writers;
|
||||
|
||||
private final Map<String, Exporter> exporters;
|
||||
|
||||
public MetricExportAutoConfiguration(MetricExportProperties properties,
|
||||
ObjectProvider<MetricsEndpointMetricReader> endpointReader,
|
||||
@ExportMetricReader ObjectProvider<List<MetricReader>> readers,
|
||||
@ExportMetricWriter ObjectProvider<Map<String, GaugeWriter>> writers,
|
||||
ObjectProvider<Map<String, Exporter>> exporters) {
|
||||
this.endpointReader = endpointReader.getIfAvailable();
|
||||
this.readers = readers.getIfAvailable();
|
||||
this.writers = writers.getIfAvailable();
|
||||
this.exporters = exporters.getIfAvailable();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(name = "metricWritersMetricExporter")
|
||||
public SchedulingConfigurer metricWritersMetricExporter(
|
||||
MetricExportProperties properties) {
|
||||
Map<String, GaugeWriter> writers = new HashMap<>();
|
||||
MetricReader reader = this.endpointReader;
|
||||
if (reader == null && !CollectionUtils.isEmpty(this.readers)) {
|
||||
reader = new CompositeMetricReader(
|
||||
this.readers.toArray(new MetricReader[this.readers.size()]));
|
||||
}
|
||||
if (reader == null && CollectionUtils.isEmpty(this.exporters)) {
|
||||
return new NoOpSchedulingConfigurer();
|
||||
}
|
||||
MetricExporters exporters = new MetricExporters(properties);
|
||||
if (reader != null) {
|
||||
if (!CollectionUtils.isEmpty(this.writers)) {
|
||||
writers.putAll(this.writers);
|
||||
}
|
||||
exporters.setReader(reader);
|
||||
exporters.setWriters(writers);
|
||||
}
|
||||
exporters.setExporters(this.exporters == null
|
||||
? Collections.<String, Exporter>emptyMap() : this.exporters);
|
||||
return exporters;
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class StatsdConfiguration {
|
||||
|
||||
@Bean
|
||||
@ExportMetricWriter
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnProperty(prefix = "spring.metrics.export.statsd", name = "host")
|
||||
public StatsdMetricWriter statsdMetricWriter(MetricExportProperties properties) {
|
||||
MetricExportProperties.Statsd statsdProperties = properties.getStatsd();
|
||||
return new StatsdMetricWriter(statsdProperties.getPrefix(),
|
||||
statsdProperties.getHost(), statsdProperties.getPort());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
protected static class MetricExportPropertiesConfiguration {
|
||||
|
||||
@Value("${spring.application.name:application}.${random.value:0000}")
|
||||
private String prefix = "";
|
||||
|
||||
private String aggregateKeyPattern = "k.d";
|
||||
|
||||
@Bean(name = "spring.metrics.export-org.springframework.boot.actuate.metrics.export.MetricExportProperties")
|
||||
@ConditionalOnMissingBean
|
||||
public MetricExportProperties metricExportProperties() {
|
||||
MetricExportProperties export = new MetricExportProperties();
|
||||
export.getRedis().setPrefix("spring.metrics"
|
||||
+ (this.prefix.length() > 0 ? "." : "") + this.prefix);
|
||||
export.getAggregate().setPrefix(this.prefix);
|
||||
export.getAggregate().setKeyPattern(this.aggregateKeyPattern);
|
||||
return export;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class NoOpSchedulingConfigurer implements SchedulingConfigurer {
|
||||
|
||||
@Override
|
||||
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,75 +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.metrics;
|
||||
|
||||
import javax.servlet.Servlet;
|
||||
import javax.servlet.ServletRegistration;
|
||||
|
||||
import org.springframework.boot.actuate.metrics.CounterService;
|
||||
import org.springframework.boot.actuate.metrics.GaugeService;
|
||||
import org.springframework.boot.actuate.metrics.web.servlet.MetricsFilter;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
import org.springframework.web.servlet.HandlerMapping;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} that records Servlet interactions
|
||||
* with a {@link CounterService} and {@link GaugeService}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
* @author Sebastian Kirsch
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnBean({ CounterService.class, GaugeService.class })
|
||||
@ConditionalOnClass({ Servlet.class, ServletRegistration.class,
|
||||
OncePerRequestFilter.class, HandlerMapping.class })
|
||||
@AutoConfigureAfter(MetricRepositoryAutoConfiguration.class)
|
||||
@ConditionalOnProperty(prefix = "management.metrics.filter", name = "enabled", matchIfMissing = true)
|
||||
@EnableConfigurationProperties({ MetricFilterProperties.class })
|
||||
public class MetricFilterAutoConfiguration {
|
||||
|
||||
private final CounterService counterService;
|
||||
|
||||
private final GaugeService gaugeService;
|
||||
|
||||
private final MetricFilterProperties properties;
|
||||
|
||||
public MetricFilterAutoConfiguration(CounterService counterService,
|
||||
GaugeService gaugeService, MetricFilterProperties properties) {
|
||||
this.counterService = counterService;
|
||||
this.gaugeService = gaugeService;
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MetricsFilter metricsFilter() {
|
||||
return new MetricsFilter(this.counterService, this.gaugeService,
|
||||
this.properties.getCounterSubmissions(),
|
||||
this.properties.getGaugeSubmissions());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,69 +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.metrics;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.boot.actuate.metrics.web.servlet.MetricsFilter;
|
||||
import org.springframework.boot.actuate.metrics.web.servlet.MetricsFilterSubmission;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* Configuration properties for the {@link MetricsFilter}.
|
||||
*
|
||||
* @author Sebastian Kirsch
|
||||
* @author Phillip Webb
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "management.metrics.filter")
|
||||
public class MetricFilterProperties {
|
||||
|
||||
/**
|
||||
* Submissions that should be made to the gauge.
|
||||
*/
|
||||
private Set<MetricsFilterSubmission> gaugeSubmissions;
|
||||
|
||||
/**
|
||||
* Submissions that should be made to the counter.
|
||||
*/
|
||||
private Set<MetricsFilterSubmission> counterSubmissions;
|
||||
|
||||
public MetricFilterProperties() {
|
||||
this.gaugeSubmissions = new HashSet<>(EnumSet.of(MetricsFilterSubmission.MERGED));
|
||||
this.counterSubmissions = new HashSet<>(
|
||||
EnumSet.of(MetricsFilterSubmission.MERGED));
|
||||
}
|
||||
|
||||
public Set<MetricsFilterSubmission> getGaugeSubmissions() {
|
||||
return this.gaugeSubmissions;
|
||||
}
|
||||
|
||||
public void setGaugeSubmissions(Set<MetricsFilterSubmission> gaugeSubmissions) {
|
||||
this.gaugeSubmissions = gaugeSubmissions;
|
||||
}
|
||||
|
||||
public Set<MetricsFilterSubmission> getCounterSubmissions() {
|
||||
return this.counterSubmissions;
|
||||
}
|
||||
|
||||
public void setCounterSubmissions(Set<MetricsFilterSubmission> counterSubmissions) {
|
||||
this.counterSubmissions = counterSubmissions;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,114 +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.metrics;
|
||||
|
||||
import com.codahale.metrics.MetricRegistry;
|
||||
|
||||
import org.springframework.boot.actuate.metrics.CounterService;
|
||||
import org.springframework.boot.actuate.metrics.GaugeService;
|
||||
import org.springframework.boot.actuate.metrics.buffer.BufferCounterService;
|
||||
import org.springframework.boot.actuate.metrics.buffer.BufferGaugeService;
|
||||
import org.springframework.boot.actuate.metrics.buffer.BufferMetricReader;
|
||||
import org.springframework.boot.actuate.metrics.buffer.CounterBuffers;
|
||||
import org.springframework.boot.actuate.metrics.buffer.GaugeBuffers;
|
||||
import org.springframework.boot.actuate.metrics.export.Exporter;
|
||||
import org.springframework.boot.actuate.metrics.export.MetricCopyExporter;
|
||||
import org.springframework.boot.actuate.metrics.repository.InMemoryMetricRepository;
|
||||
import org.springframework.boot.actuate.metrics.writer.MetricWriter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for metrics services. Creates
|
||||
* user-facing {@link GaugeService} and {@link CounterService} instances, and also back
|
||||
* end repositories to catch the data pumped into them.
|
||||
* <p>
|
||||
* In general, even if metric data needs to be stored and analysed remotely, it is
|
||||
* recommended to use in-memory storage to buffer metric updates locally as is done by the
|
||||
* default {@link CounterBuffers} and {@link GaugeBuffers}. The values can be exported
|
||||
* (e.g. on a periodic basis) using an {@link Exporter}, most implementations of which
|
||||
* have optimizations for sending data to remote repositories.
|
||||
* <p>
|
||||
* If Spring Messaging is on the classpath and a {@link MessageChannel} called
|
||||
* "metricsChannel" is also available, all metric update events are published additionally
|
||||
* as messages on that channel. Additional analysis or actions can be taken by clients
|
||||
* subscribing to that channel.
|
||||
* <p>
|
||||
* In addition if Dropwizard's metrics library is on the classpath a
|
||||
* {@link MetricRegistry} will be created and the default counter and gauge services will
|
||||
* switch to using it instead of the default repository. Users can create "special"
|
||||
* Dropwizard metrics by prefixing their metric names with the appropriate type (e.g.
|
||||
* "histogram.*", "meter.*". "timer.*") and sending them to the {@code GaugeService} or
|
||||
* {@code CounterService}.
|
||||
* <p>
|
||||
* By default all metric updates go to all {@link MetricWriter} instances in the
|
||||
* application context via a {@link MetricCopyExporter} firing every 5 seconds (disable
|
||||
* this by setting {@code spring.metrics.export.enabled=false}).
|
||||
*
|
||||
* @see GaugeService
|
||||
* @see CounterService
|
||||
* @see MetricWriter
|
||||
* @see InMemoryMetricRepository
|
||||
* @see Exporter
|
||||
* @author Dave Syer
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration
|
||||
public class MetricRepositoryAutoConfiguration {
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnMissingBean(GaugeService.class)
|
||||
static class FastMetricServicesConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public CounterBuffers counterBuffers() {
|
||||
return new CounterBuffers();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public GaugeBuffers gaugeBuffers() {
|
||||
return new GaugeBuffers();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ExportMetricReader
|
||||
@ConditionalOnMissingBean
|
||||
public BufferMetricReader actuatorMetricReader(CounterBuffers counters,
|
||||
GaugeBuffers gauges) {
|
||||
return new BufferMetricReader(counters, gauges);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(CounterService.class)
|
||||
public BufferCounterService counterService(CounterBuffers writer) {
|
||||
return new BufferCounterService(writer);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(GaugeService.class)
|
||||
public BufferGaugeService gaugeService(GaugeBuffers writer) {
|
||||
return new BufferGaugeService(writer);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,51 +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.metrics;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.actuate.metrics.writer.MessageChannelMetricWriter;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for writing metrics to a
|
||||
* {@link MessageChannel}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(MessageChannel.class)
|
||||
@ConditionalOnBean(name = "metricsChannel")
|
||||
@AutoConfigureBefore(MetricRepositoryAutoConfiguration.class)
|
||||
public class MetricsChannelAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ExportMetricWriter
|
||||
@ConditionalOnMissingBean
|
||||
public MessageChannelMetricWriter messageChannelMetricWriter(
|
||||
@Qualifier("metricsChannel") MessageChannel channel) {
|
||||
return new MessageChannelMetricWriter(channel);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,80 +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.metrics;
|
||||
|
||||
import com.codahale.metrics.MetricRegistry;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.actuate.endpoint.MetricReaderPublicMetrics;
|
||||
import org.springframework.boot.actuate.metrics.CounterService;
|
||||
import org.springframework.boot.actuate.metrics.GaugeService;
|
||||
import org.springframework.boot.actuate.metrics.dropwizard.DropwizardMetricServices;
|
||||
import org.springframework.boot.actuate.metrics.dropwizard.ReservoirFactory;
|
||||
import org.springframework.boot.actuate.metrics.reader.MetricRegistryMetricReader;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for Dropwizard-based metrics.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(MetricRegistry.class)
|
||||
@AutoConfigureBefore(MetricRepositoryAutoConfiguration.class)
|
||||
public class MetricsDropwizardAutoConfiguration {
|
||||
|
||||
private final ReservoirFactory reservoirFactory;
|
||||
|
||||
public MetricsDropwizardAutoConfiguration(
|
||||
ObjectProvider<ReservoirFactory> reservoirFactory) {
|
||||
this.reservoirFactory = reservoirFactory.getIfAvailable();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public MetricRegistry metricRegistry() {
|
||||
return new MetricRegistry();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean({ DropwizardMetricServices.class, CounterService.class,
|
||||
GaugeService.class })
|
||||
public DropwizardMetricServices dropwizardMetricServices(
|
||||
MetricRegistry metricRegistry) {
|
||||
if (this.reservoirFactory == null) {
|
||||
return new DropwizardMetricServices(metricRegistry);
|
||||
}
|
||||
else {
|
||||
return new DropwizardMetricServices(metricRegistry, this.reservoirFactory);
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MetricReaderPublicMetrics dropwizardPublicMetrics(
|
||||
MetricRegistry metricRegistry) {
|
||||
MetricRegistryMetricReader reader = new MetricRegistryMetricReader(
|
||||
metricRegistry);
|
||||
return new MetricReaderPublicMetrics(reader);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,170 +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.metrics;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.Servlet;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.catalina.startup.Tomcat;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.actuate.autoconfigure.cache.CacheStatisticsAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.cache.CacheStatisticsProvider;
|
||||
import org.springframework.boot.actuate.endpoint.CachePublicMetrics;
|
||||
import org.springframework.boot.actuate.endpoint.DataSourcePublicMetrics;
|
||||
import org.springframework.boot.actuate.endpoint.MetricReaderPublicMetrics;
|
||||
import org.springframework.boot.actuate.endpoint.PublicMetrics;
|
||||
import org.springframework.boot.actuate.endpoint.RichGaugeReaderPublicMetrics;
|
||||
import org.springframework.boot.actuate.endpoint.SystemPublicMetrics;
|
||||
import org.springframework.boot.actuate.endpoint.TomcatPublicMetrics;
|
||||
import org.springframework.boot.actuate.metrics.integration.SpringIntegrationMetricReader;
|
||||
import org.springframework.boot.actuate.metrics.reader.CompositeMetricReader;
|
||||
import org.springframework.boot.actuate.metrics.reader.MetricReader;
|
||||
import org.springframework.boot.actuate.metrics.rich.RichGaugeReader;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration;
|
||||
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.SearchStrategy;
|
||||
import org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadataProvider;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.integration.config.EnableIntegrationManagement;
|
||||
import org.springframework.integration.support.management.IntegrationManagementConfigurer;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for {@link PublicMetrics}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Phillip Webb
|
||||
* @author Johannes Edmeier
|
||||
* @author Artem Bilan
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@AutoConfigureBefore(EndpointAutoConfiguration.class)
|
||||
@AutoConfigureAfter({ DataSourceAutoConfiguration.class, CacheAutoConfiguration.class,
|
||||
MetricRepositoryAutoConfiguration.class, CacheStatisticsAutoConfiguration.class,
|
||||
IntegrationAutoConfiguration.class })
|
||||
public class PublicMetricsAutoConfiguration {
|
||||
|
||||
private final List<MetricReader> metricReaders;
|
||||
|
||||
public PublicMetricsAutoConfiguration(
|
||||
@ExportMetricReader ObjectProvider<List<MetricReader>> metricReaders) {
|
||||
this.metricReaders = metricReaders.getIfAvailable();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SystemPublicMetrics systemPublicMetrics() {
|
||||
return new SystemPublicMetrics();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MetricReaderPublicMetrics metricReaderPublicMetrics() {
|
||||
return new MetricReaderPublicMetrics(
|
||||
new CompositeMetricReader(this.metricReaders == null ? new MetricReader[0]
|
||||
: this.metricReaders
|
||||
.toArray(new MetricReader[this.metricReaders.size()])));
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(RichGaugeReader.class)
|
||||
public RichGaugeReaderPublicMetrics richGaugePublicMetrics(
|
||||
RichGaugeReader richGaugeReader) {
|
||||
return new RichGaugeReaderPublicMetrics(richGaugeReader);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(DataSource.class)
|
||||
@ConditionalOnBean(DataSource.class)
|
||||
static class DataSourceMetricsConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnBean(DataSourcePoolMetadataProvider.class)
|
||||
public DataSourcePublicMetrics dataSourcePublicMetrics() {
|
||||
return new DataSourcePublicMetrics();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass({ Servlet.class, Tomcat.class })
|
||||
@ConditionalOnWebApplication
|
||||
static class TomcatMetricsConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public TomcatPublicMetrics tomcatPublicMetrics() {
|
||||
return new TomcatPublicMetrics();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(CacheManager.class)
|
||||
@ConditionalOnBean(CacheManager.class)
|
||||
static class CacheStatisticsConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnBean(CacheStatisticsProvider.class)
|
||||
public CachePublicMetrics cachePublicMetrics(
|
||||
Map<String, CacheManager> cacheManagers,
|
||||
Collection<CacheStatisticsProvider<?>> statisticsProviders) {
|
||||
return new CachePublicMetrics(cacheManagers, statisticsProviders);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(EnableIntegrationManagement.class)
|
||||
static class IntegrationMetricsConfiguration {
|
||||
|
||||
@Bean(name = IntegrationManagementConfigurer.MANAGEMENT_CONFIGURER_NAME)
|
||||
@ConditionalOnMissingBean(value = IntegrationManagementConfigurer.class, name = IntegrationManagementConfigurer.MANAGEMENT_CONFIGURER_NAME, search = SearchStrategy.CURRENT)
|
||||
public IntegrationManagementConfigurer managementConfigurer() {
|
||||
IntegrationManagementConfigurer configurer = new IntegrationManagementConfigurer();
|
||||
configurer.setDefaultCountsEnabled(true);
|
||||
configurer.setDefaultStatsEnabled(true);
|
||||
return configurer;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(name = "springIntegrationPublicMetrics")
|
||||
public MetricReaderPublicMetrics springIntegrationPublicMetrics(
|
||||
IntegrationManagementConfigurer managementConfigurer) {
|
||||
return new MetricReaderPublicMetrics(
|
||||
new SpringIntegrationMetricReader(managementConfigurer));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,20 +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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Classes for general Actuator auto-configuration concerns.
|
||||
*/
|
||||
package org.springframework.boot.actuate.autoconfigure;
|
||||
@@ -1,48 +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.security;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.ManagementEndpointPathResolver;
|
||||
import org.springframework.boot.actuate.autoconfigure.web.ManagementServerProperties;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration;
|
||||
import org.springframework.boot.endpoint.EndpointPathResolver;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
|
||||
/**
|
||||
* Security configuration for management endpoints.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
|
||||
@ConditionalOnClass({ EnableWebSecurity.class })
|
||||
@AutoConfigureBefore(SecurityAutoConfiguration.class)
|
||||
public class ManagementWebSecurityAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public EndpointPathResolver managementEndpointPathResolver(
|
||||
ManagementServerProperties properties) {
|
||||
return new ManagementEndpointPathResolver(properties);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,41 +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.trace;
|
||||
|
||||
import org.springframework.boot.actuate.trace.InMemoryTraceRepository;
|
||||
import org.springframework.boot.actuate.trace.TraceRepository;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for {@link TraceRepository tracing}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration
|
||||
public class TraceRepositoryAutoConfiguration {
|
||||
|
||||
@ConditionalOnMissingBean(TraceRepository.class)
|
||||
@Bean
|
||||
public InMemoryTraceRepository traceRepository() {
|
||||
return new InMemoryTraceRepository();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.autoconfigure.trace;
|
||||
|
||||
import javax.servlet.Servlet;
|
||||
import javax.servlet.ServletRegistration;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.actuate.trace.TraceProperties;
|
||||
import org.springframework.boot.actuate.trace.TraceRepository;
|
||||
import org.springframework.boot.actuate.trace.WebRequestTraceFilter;
|
||||
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.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorAttributes;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for {@link WebRequestTraceFilter
|
||||
* tracing}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, ServletRegistration.class })
|
||||
@AutoConfigureAfter(TraceRepositoryAutoConfiguration.class)
|
||||
@ConditionalOnProperty(prefix = "management.trace.filter", name = "enabled", matchIfMissing = true)
|
||||
@EnableConfigurationProperties(TraceProperties.class)
|
||||
public class TraceWebFilterAutoConfiguration {
|
||||
|
||||
private final TraceRepository traceRepository;
|
||||
|
||||
private final TraceProperties traceProperties;
|
||||
|
||||
private final ErrorAttributes errorAttributes;
|
||||
|
||||
public TraceWebFilterAutoConfiguration(TraceRepository traceRepository,
|
||||
TraceProperties traceProperties,
|
||||
ObjectProvider<ErrorAttributes> errorAttributes) {
|
||||
this.traceRepository = traceRepository;
|
||||
this.traceProperties = traceProperties;
|
||||
this.errorAttributes = errorAttributes.getIfAvailable();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public WebRequestTraceFilter webRequestLoggingFilter(BeanFactory beanFactory) {
|
||||
WebRequestTraceFilter filter = new WebRequestTraceFilter(this.traceRepository,
|
||||
this.traceProperties);
|
||||
if (this.errorAttributes != null) {
|
||||
filter.setErrorAttributes(this.errorAttributes);
|
||||
}
|
||||
return filter;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,127 +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.web;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
import org.springframework.boot.autoconfigure.security.SecurityPrerequisite;
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||
import org.springframework.boot.web.server.Ssl;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Properties for the management server (e.g. port and path settings).
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Stephane Nicoll
|
||||
* @author Vedran Pavic
|
||||
* @see ServerProperties
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "management", ignoreUnknownFields = true)
|
||||
public class ManagementServerProperties implements SecurityPrerequisite {
|
||||
|
||||
/**
|
||||
* Management endpoint HTTP port. Use the same port as the application by default.
|
||||
*/
|
||||
private Integer port;
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private Ssl ssl;
|
||||
|
||||
/**
|
||||
* Network address that the management endpoints should bind to.
|
||||
*/
|
||||
private InetAddress address;
|
||||
|
||||
/**
|
||||
* Management endpoint context-path.
|
||||
*/
|
||||
private String contextPath = "/application";
|
||||
|
||||
/**
|
||||
* Add the "X-Application-Context" HTTP header in each response.
|
||||
*/
|
||||
private boolean addApplicationContextHeader = false;
|
||||
|
||||
/**
|
||||
* Returns the management port or {@code null} if the
|
||||
* {@link ServerProperties#getPort() server port} should be used.
|
||||
* @return the port
|
||||
* @see #setPort(Integer)
|
||||
*/
|
||||
public Integer getPort() {
|
||||
return this.port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the port of the management server, use {@code null} if the
|
||||
* {@link ServerProperties#getPort() server port} should be used. To disable use 0.
|
||||
* @param port the port
|
||||
*/
|
||||
public void setPort(Integer port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public Ssl getSsl() {
|
||||
return this.ssl;
|
||||
}
|
||||
|
||||
public void setSsl(Ssl ssl) {
|
||||
this.ssl = ssl;
|
||||
}
|
||||
|
||||
public InetAddress getAddress() {
|
||||
return this.address;
|
||||
}
|
||||
|
||||
public void setAddress(InetAddress address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the context path with no trailing slash (i.e. the '/' root context is
|
||||
* represented as the empty string).
|
||||
* @return the context path (no trailing slash)
|
||||
*/
|
||||
public String getContextPath() {
|
||||
return this.contextPath;
|
||||
}
|
||||
|
||||
public void setContextPath(String contextPath) {
|
||||
Assert.notNull(contextPath, "ContextPath must not be null");
|
||||
this.contextPath = cleanContextPath(contextPath);
|
||||
}
|
||||
|
||||
private String cleanContextPath(String contextPath) {
|
||||
if (StringUtils.hasText(contextPath) && contextPath.endsWith("/")) {
|
||||
return contextPath.substring(0, contextPath.length() - 1);
|
||||
}
|
||||
return contextPath;
|
||||
}
|
||||
|
||||
public boolean getAddApplicationContextHeader() {
|
||||
return this.addApplicationContextHeader;
|
||||
}
|
||||
|
||||
public void setAddApplicationContextHeader(boolean addApplicationContextHeader) {
|
||||
this.addApplicationContextHeader = addApplicationContextHeader;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,20 +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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Auto-configuration for Actuator's web concerns.
|
||||
*/
|
||||
package org.springframework.boot.actuate.autoconfigure.web;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.endpoint;
|
||||
package org.springframework.boot.actuate.beans;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -23,8 +23,8 @@ import java.util.Map;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.boot.endpoint.Endpoint;
|
||||
import org.springframework.boot.endpoint.ReadOperation;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -35,6 +35,7 @@ import org.springframework.util.StringUtils;
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Endpoint(id = "beans")
|
||||
public class BeansEndpoint {
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Actuator web server support.
|
||||
*
|
||||
* Actuator support relating to Spring Beans.
|
||||
*/
|
||||
package org.springframework.boot.actuate.web.server;
|
||||
package org.springframework.boot.actuate.beans;
|
||||
@@ -14,16 +14,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.endpoint;
|
||||
package org.springframework.boot.actuate.cache;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.actuate.cache.CacheStatistics;
|
||||
import org.springframework.boot.actuate.cache.CacheStatisticsProvider;
|
||||
import org.springframework.boot.actuate.metrics.Metric;
|
||||
import org.springframework.boot.actuate.metrics.PublicMetrics;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.transaction.TransactionAwareCacheDecorator;
|
||||
@@ -36,7 +35,7 @@ import org.springframework.util.MultiValueMap;
|
||||
* A {@link PublicMetrics} implementation that provides cache statistics.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.3.0
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class CachePublicMetrics implements PublicMetrics {
|
||||
|
||||
@@ -15,6 +15,6 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Classes for cache statistics.
|
||||
* Actuator support for cache statistics.
|
||||
*/
|
||||
package org.springframework.boot.actuate.cache;
|
||||
|
||||
@@ -14,12 +14,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.health;
|
||||
package org.springframework.boot.actuate.cassandra;
|
||||
|
||||
import com.datastax.driver.core.ResultSet;
|
||||
import com.datastax.driver.core.querybuilder.QueryBuilder;
|
||||
import com.datastax.driver.core.querybuilder.Select;
|
||||
|
||||
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.data.cassandra.core.CassandraOperations;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -28,7 +31,7 @@ import org.springframework.util.Assert;
|
||||
* Cassandra data stores.
|
||||
*
|
||||
* @author Julien Dubois
|
||||
* @since 1.3.0
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class CassandraHealthIndicator extends AbstractHealthIndicator {
|
||||
|
||||
@@ -1,67 +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.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* The specific access level granted to the cloud foundry user that's calling the
|
||||
* endpoints.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
enum AccessLevel {
|
||||
|
||||
/**
|
||||
* Restricted access to a limited set of endpoints.
|
||||
*/
|
||||
RESTRICTED("", "health", "info"),
|
||||
|
||||
/**
|
||||
* Full access to all endpoints.
|
||||
*/
|
||||
FULL;
|
||||
|
||||
private static final String REQUEST_ATTRIBUTE = "cloudFoundryAccessLevel";
|
||||
|
||||
private final List<String> endpointPaths;
|
||||
|
||||
AccessLevel(String... endpointPaths) {
|
||||
this.endpointPaths = Arrays.asList(endpointPaths);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the access level should allow access to the specified endpoint path.
|
||||
* @param endpointPath the endpoint path
|
||||
* @return {@code true} if access is allowed
|
||||
*/
|
||||
public boolean isAccessAllowed(String endpointPath) {
|
||||
return this.endpointPaths.isEmpty() || this.endpointPaths.contains(endpointPath);
|
||||
}
|
||||
|
||||
public void put(HttpServletRequest request) {
|
||||
request.setAttribute(REQUEST_ATTRIBUTE, this);
|
||||
}
|
||||
|
||||
public static AccessLevel get(HttpServletRequest request) {
|
||||
return (AccessLevel) request.getAttribute(REQUEST_ATTRIBUTE);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,136 +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.Arrays;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.infrastructure.EndpointProvider;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.infrastructure.ServletEndpointAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnCloudPlatform;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
||||
import org.springframework.boot.cloud.CloudPlatform;
|
||||
import org.springframework.boot.endpoint.web.EndpointMapping;
|
||||
import org.springframework.boot.endpoint.web.WebEndpointOperation;
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} to expose actuator endpoints for
|
||||
* cloud foundry to use.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnProperty(prefix = "management.cloudfoundry", name = "enabled", matchIfMissing = true)
|
||||
@AutoConfigureAfter(ServletEndpointAutoConfiguration.class)
|
||||
@ConditionalOnCloudPlatform(CloudPlatform.CLOUD_FOUNDRY)
|
||||
public class CloudFoundryActuatorAutoConfiguration {
|
||||
|
||||
/**
|
||||
* Configuration for MVC endpoints on Cloud Foundry.
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
|
||||
@ConditionalOnClass(DispatcherServlet.class)
|
||||
@ConditionalOnBean(DispatcherServlet.class)
|
||||
static class MvcWebEndpointConfiguration {
|
||||
|
||||
@Bean
|
||||
public CloudFoundryWebEndpointServletHandlerMapping cloudFoundryWebEndpointServletHandlerMapping(
|
||||
EndpointProvider<WebEndpointOperation> provider, Environment environment,
|
||||
RestTemplateBuilder builder) {
|
||||
return new CloudFoundryWebEndpointServletHandlerMapping(
|
||||
new EndpointMapping("/cloudfoundryapplication"),
|
||||
provider.getEndpoints(), getCorsConfiguration(),
|
||||
getSecurityInterceptor(builder, environment));
|
||||
}
|
||||
|
||||
private CloudFoundrySecurityInterceptor getSecurityInterceptor(
|
||||
RestTemplateBuilder restTemplateBuilder, Environment environment) {
|
||||
CloudFoundrySecurityService cloudfoundrySecurityService = getCloudFoundrySecurityService(
|
||||
restTemplateBuilder, environment);
|
||||
TokenValidator tokenValidator = new TokenValidator(
|
||||
cloudfoundrySecurityService);
|
||||
return new CloudFoundrySecurityInterceptor(tokenValidator,
|
||||
cloudfoundrySecurityService,
|
||||
environment.getProperty("vcap.application.application_id"));
|
||||
}
|
||||
|
||||
private CloudFoundrySecurityService getCloudFoundrySecurityService(
|
||||
RestTemplateBuilder restTemplateBuilder, Environment environment) {
|
||||
String cloudControllerUrl = environment
|
||||
.getProperty("vcap.application.cf_api");
|
||||
boolean skipSslValidation = environment.getProperty(
|
||||
"management.cloudfoundry.skip-ssl-validation", Boolean.class, false);
|
||||
return (cloudControllerUrl == null ? null
|
||||
: new CloudFoundrySecurityService(restTemplateBuilder,
|
||||
cloudControllerUrl, skipSslValidation));
|
||||
}
|
||||
|
||||
private CorsConfiguration getCorsConfiguration() {
|
||||
CorsConfiguration corsConfiguration = new CorsConfiguration();
|
||||
corsConfiguration.addAllowedOrigin(CorsConfiguration.ALL);
|
||||
corsConfiguration.setAllowedMethods(
|
||||
Arrays.asList(HttpMethod.GET.name(), HttpMethod.POST.name()));
|
||||
corsConfiguration.setAllowedHeaders(
|
||||
Arrays.asList("Authorization", "X-Cf-App-Instance", "Content-Type"));
|
||||
return corsConfiguration;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link WebSecurityConfigurer} to tell Spring Security to ignore cloudfoundry
|
||||
* specific paths. The Cloud foundry endpoints are protected by their own security
|
||||
* interceptor.
|
||||
*/
|
||||
@ConditionalOnClass(WebSecurity.class)
|
||||
@Order(SecurityProperties.IGNORED_ORDER)
|
||||
@Configuration
|
||||
public static class IgnoredPathsWebSecurityConfigurer
|
||||
implements WebSecurityConfigurer<WebSecurity> {
|
||||
|
||||
@Override
|
||||
public void init(WebSecurity builder) throws Exception {
|
||||
builder.ignoring().requestMatchers(
|
||||
new AntPathRequestMatcher("/cloudfoundryapplication/**"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(WebSecurity builder) throws Exception {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,92 +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 org.springframework.http.HttpStatus;
|
||||
|
||||
/**
|
||||
* Authorization exceptions thrown to limit access to the endpoints.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
class CloudFoundryAuthorizationException extends RuntimeException {
|
||||
|
||||
private final Reason reason;
|
||||
|
||||
CloudFoundryAuthorizationException(Reason reason, String message) {
|
||||
this(reason, message, null);
|
||||
}
|
||||
|
||||
CloudFoundryAuthorizationException(Reason reason, String message, Throwable cause) {
|
||||
super(message);
|
||||
this.reason = reason;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the status code that should be returned to the client.
|
||||
* @return the HTTP status code
|
||||
*/
|
||||
public HttpStatus getStatusCode() {
|
||||
return getReason().getStatus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the reason why the authorization exception was thrown.
|
||||
* @return the reason
|
||||
*/
|
||||
public Reason getReason() {
|
||||
return this.reason;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reasons why the exception can be thrown.
|
||||
*/
|
||||
enum Reason {
|
||||
|
||||
ACCESS_DENIED(HttpStatus.FORBIDDEN),
|
||||
|
||||
INVALID_AUDIENCE(HttpStatus.UNAUTHORIZED),
|
||||
|
||||
INVALID_ISSUER(HttpStatus.UNAUTHORIZED),
|
||||
|
||||
INVALID_KEY_ID(HttpStatus.UNAUTHORIZED),
|
||||
|
||||
INVALID_SIGNATURE(HttpStatus.UNAUTHORIZED),
|
||||
|
||||
INVALID_TOKEN(HttpStatus.UNAUTHORIZED),
|
||||
|
||||
MISSING_AUTHORIZATION(HttpStatus.UNAUTHORIZED),
|
||||
|
||||
TOKEN_EXPIRED(HttpStatus.UNAUTHORIZED),
|
||||
|
||||
UNSUPPORTED_TOKEN_SIGNING_ALGORITHM(HttpStatus.UNAUTHORIZED),
|
||||
|
||||
SERVICE_UNAVAILABLE(HttpStatus.SERVICE_UNAVAILABLE);
|
||||
|
||||
private final HttpStatus status;
|
||||
|
||||
Reason(HttpStatus status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public HttpStatus getStatus() {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,145 +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 javax.servlet.http.HttpServletRequest;
|
||||
|
||||
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.util.StringUtils;
|
||||
import org.springframework.web.cors.CorsUtils;
|
||||
|
||||
/**
|
||||
* Security interceptor to validate the cloud foundry token.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
class CloudFoundrySecurityInterceptor {
|
||||
|
||||
private static final Log logger = LogFactory
|
||||
.getLog(CloudFoundrySecurityInterceptor.class);
|
||||
|
||||
private final TokenValidator tokenValidator;
|
||||
|
||||
private final CloudFoundrySecurityService cloudFoundrySecurityService;
|
||||
|
||||
private final String applicationId;
|
||||
|
||||
private static SecurityResponse SUCCESS = SecurityResponse.success();
|
||||
|
||||
CloudFoundrySecurityInterceptor(TokenValidator tokenValidator,
|
||||
CloudFoundrySecurityService cloudFoundrySecurityService,
|
||||
String applicationId) {
|
||||
this.tokenValidator = tokenValidator;
|
||||
this.cloudFoundrySecurityService = cloudFoundrySecurityService;
|
||||
this.applicationId = applicationId;
|
||||
}
|
||||
|
||||
SecurityResponse preHandle(HttpServletRequest request, String endpointId) {
|
||||
if (CorsUtils.isPreFlightRequest(request)) {
|
||||
return SecurityResponse.success();
|
||||
}
|
||||
try {
|
||||
if (!StringUtils.hasText(this.applicationId)) {
|
||||
throw new CloudFoundryAuthorizationException(
|
||||
CloudFoundryAuthorizationException.Reason.SERVICE_UNAVAILABLE,
|
||||
"Application id is not available");
|
||||
}
|
||||
if (this.cloudFoundrySecurityService == null) {
|
||||
throw new CloudFoundryAuthorizationException(
|
||||
CloudFoundryAuthorizationException.Reason.SERVICE_UNAVAILABLE,
|
||||
"Cloud controller URL is not available");
|
||||
}
|
||||
if (HttpMethod.OPTIONS.matches(request.getMethod())) {
|
||||
return SUCCESS;
|
||||
}
|
||||
check(request, endpointId);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
logger.error(ex);
|
||||
if (ex instanceof CloudFoundryAuthorizationException) {
|
||||
CloudFoundryAuthorizationException cfException = (CloudFoundryAuthorizationException) ex;
|
||||
return new SecurityResponse(cfException.getStatusCode(),
|
||||
"{\"security_error\":\"" + cfException.getMessage() + "\"}");
|
||||
}
|
||||
return new SecurityResponse(HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
ex.getMessage());
|
||||
}
|
||||
return SecurityResponse.success();
|
||||
}
|
||||
|
||||
private void check(HttpServletRequest request, String path) throws Exception {
|
||||
Token token = getToken(request);
|
||||
this.tokenValidator.validate(token);
|
||||
AccessLevel accessLevel = this.cloudFoundrySecurityService
|
||||
.getAccessLevel(token.toString(), this.applicationId);
|
||||
if (!accessLevel.isAccessAllowed(path)) {
|
||||
throw new CloudFoundryAuthorizationException(
|
||||
CloudFoundryAuthorizationException.Reason.ACCESS_DENIED,
|
||||
"Access denied");
|
||||
}
|
||||
accessLevel.put(request);
|
||||
}
|
||||
|
||||
private Token getToken(HttpServletRequest request) {
|
||||
String authorization = request.getHeader("Authorization");
|
||||
String bearerPrefix = "bearer ";
|
||||
if (authorization == null
|
||||
|| !authorization.toLowerCase().startsWith(bearerPrefix)) {
|
||||
throw new CloudFoundryAuthorizationException(
|
||||
CloudFoundryAuthorizationException.Reason.MISSING_AUTHORIZATION,
|
||||
"Authorization header is missing or invalid");
|
||||
}
|
||||
return new Token(authorization.substring(bearerPrefix.length()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Response from the security interceptor.
|
||||
*/
|
||||
static class SecurityResponse {
|
||||
|
||||
private final HttpStatus status;
|
||||
|
||||
private final String message;
|
||||
|
||||
SecurityResponse(HttpStatus status) {
|
||||
this(status, null);
|
||||
}
|
||||
|
||||
SecurityResponse(HttpStatus status, String message) {
|
||||
this.status = status;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public HttpStatus getStatus() {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return this.message;
|
||||
}
|
||||
|
||||
static SecurityResponse success() {
|
||||
return new SecurityResponse(HttpStatus.OK);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,146 +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.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.actuate.cloudfoundry.CloudFoundryAuthorizationException.Reason;
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.RequestEntity;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.client.HttpClientErrorException;
|
||||
import org.springframework.web.client.HttpServerErrorException;
|
||||
import org.springframework.web.client.HttpStatusCodeException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* Cloud Foundry security service to handle REST calls to the cloud controller and UAA.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
class CloudFoundrySecurityService {
|
||||
|
||||
private final RestTemplate restTemplate;
|
||||
|
||||
private final String cloudControllerUrl;
|
||||
|
||||
private String uaaUrl;
|
||||
|
||||
CloudFoundrySecurityService(RestTemplateBuilder restTemplateBuilder,
|
||||
String cloudControllerUrl, boolean skipSslValidation) {
|
||||
Assert.notNull(restTemplateBuilder, "RestTemplateBuilder must not be null");
|
||||
Assert.notNull(cloudControllerUrl, "CloudControllerUrl must not be null");
|
||||
if (skipSslValidation) {
|
||||
restTemplateBuilder = restTemplateBuilder
|
||||
.requestFactory(SkipSslVerificationHttpRequestFactory.class);
|
||||
}
|
||||
this.restTemplate = restTemplateBuilder.build();
|
||||
this.cloudControllerUrl = cloudControllerUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the access level that should be granted to the given token.
|
||||
* @param token the token
|
||||
* @param applicationId the cloud foundry application ID
|
||||
* @return the access level that should be granted
|
||||
* @throws CloudFoundryAuthorizationException if the token is not authorized
|
||||
*/
|
||||
public AccessLevel getAccessLevel(String token, String applicationId)
|
||||
throws CloudFoundryAuthorizationException {
|
||||
try {
|
||||
URI uri = getPermissionsUri(applicationId);
|
||||
RequestEntity<?> request = RequestEntity.get(uri)
|
||||
.header("Authorization", "bearer " + token).build();
|
||||
Map<?, ?> body = this.restTemplate.exchange(request, Map.class).getBody();
|
||||
if (Boolean.TRUE.equals(body.get("read_sensitive_data"))) {
|
||||
return AccessLevel.FULL;
|
||||
}
|
||||
return AccessLevel.RESTRICTED;
|
||||
}
|
||||
catch (HttpClientErrorException ex) {
|
||||
if (ex.getStatusCode().equals(HttpStatus.FORBIDDEN)) {
|
||||
throw new CloudFoundryAuthorizationException(Reason.ACCESS_DENIED,
|
||||
"Access denied");
|
||||
}
|
||||
throw new CloudFoundryAuthorizationException(Reason.INVALID_TOKEN,
|
||||
"Invalid token", ex);
|
||||
}
|
||||
catch (HttpServerErrorException ex) {
|
||||
throw new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE,
|
||||
"Cloud controller not reachable");
|
||||
}
|
||||
}
|
||||
|
||||
private URI getPermissionsUri(String applicationId) {
|
||||
try {
|
||||
return new URI(this.cloudControllerUrl + "/v2/apps/" + applicationId
|
||||
+ "/permissions");
|
||||
}
|
||||
catch (URISyntaxException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all token keys known by the UAA.
|
||||
* @return a list of token keys
|
||||
*/
|
||||
public Map<String, String> fetchTokenKeys() {
|
||||
try {
|
||||
return extractTokenKeys(this.restTemplate
|
||||
.getForObject(getUaaUrl() + "/token_keys", Map.class));
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
throw new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE,
|
||||
"UAA not reachable");
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, String> extractTokenKeys(Map<?, ?> response) {
|
||||
Map<String, String> tokenKeys = new HashMap<>();
|
||||
for (Object key : (List<?>) response.get("keys")) {
|
||||
Map<?, ?> tokenKey = (Map<?, ?>) key;
|
||||
tokenKeys.put((String) tokenKey.get("kid"), (String) tokenKey.get("value"));
|
||||
}
|
||||
return tokenKeys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the URL of the UAA.
|
||||
* @return the UAA url
|
||||
*/
|
||||
public String getUaaUrl() {
|
||||
if (this.uaaUrl == null) {
|
||||
try {
|
||||
Map<?, ?> response = this.restTemplate
|
||||
.getForObject(this.cloudControllerUrl + "/info", Map.class);
|
||||
this.uaaUrl = (String) response.get("token_endpoint");
|
||||
}
|
||||
catch (HttpStatusCodeException ex) {
|
||||
throw new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE,
|
||||
"Unable to fetch token keys from UAA");
|
||||
}
|
||||
}
|
||||
return this.uaaUrl;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,198 +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.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
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.endpoint.EndpointInfo;
|
||||
import org.springframework.boot.endpoint.OperationInvoker;
|
||||
import org.springframework.boot.endpoint.ParameterMappingException;
|
||||
import org.springframework.boot.endpoint.web.EndpointLinksResolver;
|
||||
import org.springframework.boot.endpoint.web.EndpointMapping;
|
||||
import org.springframework.boot.endpoint.web.Link;
|
||||
import org.springframework.boot.endpoint.web.WebEndpointOperation;
|
||||
import org.springframework.boot.endpoint.web.WebEndpointResponse;
|
||||
import org.springframework.boot.endpoint.web.mvc.AbstractWebEndpointServletHandlerMapping;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.servlet.HandlerMapping;
|
||||
import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
|
||||
|
||||
/**
|
||||
* A custom {@link RequestMappingInfoHandlerMapping} that makes web endpoints available on
|
||||
* Cloudfoundry specific URLS over HTTP using Spring MVC.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
class CloudFoundryWebEndpointServletHandlerMapping
|
||||
extends AbstractWebEndpointServletHandlerMapping {
|
||||
|
||||
private final Method handle = ReflectionUtils.findMethod(OperationHandler.class,
|
||||
"handle", HttpServletRequest.class, Map.class);
|
||||
|
||||
private final Method links = ReflectionUtils.findMethod(
|
||||
CloudFoundryWebEndpointServletHandlerMapping.class, "links",
|
||||
HttpServletRequest.class, HttpServletResponse.class);
|
||||
|
||||
private static final Log logger = LogFactory
|
||||
.getLog(CloudFoundryWebEndpointServletHandlerMapping.class);
|
||||
|
||||
private final CloudFoundrySecurityInterceptor securityInterceptor;
|
||||
|
||||
private final EndpointLinksResolver endpointLinksResolver = new EndpointLinksResolver();
|
||||
|
||||
CloudFoundryWebEndpointServletHandlerMapping(EndpointMapping endpointMapping,
|
||||
Collection<EndpointInfo<WebEndpointOperation>> webEndpoints,
|
||||
CorsConfiguration corsConfiguration,
|
||||
CloudFoundrySecurityInterceptor securityInterceptor) {
|
||||
super(endpointMapping, webEndpoints, corsConfiguration);
|
||||
this.securityInterceptor = securityInterceptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Method getLinks() {
|
||||
return this.links;
|
||||
}
|
||||
|
||||
@ResponseBody
|
||||
private Map<String, Map<String, Link>> links(HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
CloudFoundrySecurityInterceptor.SecurityResponse securityResponse = this.securityInterceptor
|
||||
.preHandle(request, "");
|
||||
if (!securityResponse.getStatus().equals(HttpStatus.OK)) {
|
||||
sendFailureResponse(response, securityResponse);
|
||||
}
|
||||
AccessLevel accessLevel = AccessLevel.get(request);
|
||||
Map<String, Link> links = this.endpointLinksResolver.resolveLinks(getEndpoints(),
|
||||
request.getRequestURL().toString());
|
||||
Map<String, Link> filteredLinks = new LinkedHashMap<>();
|
||||
if (accessLevel == null) {
|
||||
return Collections.singletonMap("_links", filteredLinks);
|
||||
}
|
||||
filteredLinks = links.entrySet().stream()
|
||||
.filter((e) -> e.getKey().equals("self")
|
||||
|| accessLevel.isAccessAllowed(e.getKey()))
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||
return Collections.singletonMap("_links", filteredLinks);
|
||||
}
|
||||
|
||||
private void sendFailureResponse(HttpServletResponse response,
|
||||
CloudFoundrySecurityInterceptor.SecurityResponse securityResponse) {
|
||||
try {
|
||||
response.sendError(securityResponse.getStatus().value(),
|
||||
securityResponse.getMessage());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
logger.debug("Failed to send error response", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerMappingForOperation(WebEndpointOperation operation) {
|
||||
registerMapping(createRequestMappingInfo(operation),
|
||||
new OperationHandler(operation.getInvoker(), operation.getId(),
|
||||
this.securityInterceptor),
|
||||
this.handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler which has the handler method and security interceptor.
|
||||
*/
|
||||
final class OperationHandler {
|
||||
|
||||
private final OperationInvoker operationInvoker;
|
||||
|
||||
private final String endpointId;
|
||||
|
||||
private final CloudFoundrySecurityInterceptor securityInterceptor;
|
||||
|
||||
OperationHandler(OperationInvoker operationInvoker, String id,
|
||||
CloudFoundrySecurityInterceptor securityInterceptor) {
|
||||
this.operationInvoker = operationInvoker;
|
||||
this.endpointId = id;
|
||||
this.securityInterceptor = securityInterceptor;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@ResponseBody
|
||||
public Object handle(HttpServletRequest request,
|
||||
@RequestBody(required = false) Map<String, String> body) {
|
||||
CloudFoundrySecurityInterceptor.SecurityResponse securityResponse = this.securityInterceptor
|
||||
.preHandle(request, this.endpointId);
|
||||
if (!securityResponse.getStatus().equals(HttpStatus.OK)) {
|
||||
return failureResponse(securityResponse);
|
||||
}
|
||||
Map<String, Object> arguments = new HashMap<>((Map<String, String>) request
|
||||
.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE));
|
||||
HttpMethod httpMethod = HttpMethod.valueOf(request.getMethod());
|
||||
if (body != null && HttpMethod.POST == httpMethod) {
|
||||
arguments.putAll(body);
|
||||
}
|
||||
request.getParameterMap().forEach((name, values) -> arguments.put(name,
|
||||
values.length == 1 ? values[0] : Arrays.asList(values)));
|
||||
try {
|
||||
return handleResult(this.operationInvoker.invoke(arguments), httpMethod);
|
||||
}
|
||||
catch (ParameterMappingException ex) {
|
||||
return new ResponseEntity<Void>(HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
private Object failureResponse(
|
||||
CloudFoundrySecurityInterceptor.SecurityResponse response) {
|
||||
return handleResult(new WebEndpointResponse<>(response.getMessage(),
|
||||
response.getStatus().value()));
|
||||
}
|
||||
|
||||
private Object handleResult(Object result) {
|
||||
return handleResult(result, null);
|
||||
}
|
||||
|
||||
private Object handleResult(Object result, HttpMethod httpMethod) {
|
||||
if (result == null) {
|
||||
return new ResponseEntity<>(httpMethod == HttpMethod.GET
|
||||
? HttpStatus.NOT_FOUND : HttpStatus.NO_CONTENT);
|
||||
}
|
||||
if (!(result instanceof WebEndpointResponse)) {
|
||||
return result;
|
||||
}
|
||||
WebEndpointResponse<?> response = (WebEndpointResponse<?>) result;
|
||||
return new ResponseEntity<Object>(response.getBody(),
|
||||
HttpStatus.valueOf(response.getStatus()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,93 +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.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLSession;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||
|
||||
/**
|
||||
* {@link SimpleClientHttpRequestFactory} that skips SSL certificate verification.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
class SkipSslVerificationHttpRequestFactory extends SimpleClientHttpRequestFactory {
|
||||
|
||||
@Override
|
||||
protected void prepareConnection(HttpURLConnection connection, String httpMethod)
|
||||
throws IOException {
|
||||
if (connection instanceof HttpsURLConnection) {
|
||||
prepareHttpsConnection((HttpsURLConnection) connection);
|
||||
}
|
||||
super.prepareConnection(connection, httpMethod);
|
||||
}
|
||||
|
||||
private void prepareHttpsConnection(HttpsURLConnection connection) {
|
||||
connection.setHostnameVerifier(new SkipHostnameVerifier());
|
||||
try {
|
||||
connection.setSSLSocketFactory(createSslSocketFactory());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
private SSLSocketFactory createSslSocketFactory() throws Exception {
|
||||
SSLContext context = SSLContext.getInstance("TLS");
|
||||
context.init(null, new TrustManager[] { new SkipX509TrustManager() },
|
||||
new SecureRandom());
|
||||
return context.getSocketFactory();
|
||||
}
|
||||
|
||||
private class SkipHostnameVerifier implements HostnameVerifier {
|
||||
|
||||
@Override
|
||||
public boolean verify(String s, SSLSession sslSession) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class SkipX509TrustManager implements X509TrustManager {
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return new X509Certificate[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] chain, String authType) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] chain, String authType) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.cloudfoundry;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.json.JsonParserFactory;
|
||||
import org.springframework.util.Base64Utils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* The JSON web token provided with each request that originates from Cloud Foundry.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
class Token {
|
||||
|
||||
private static final Charset UTF_8 = Charset.forName("UTF-8");
|
||||
|
||||
private final String encoded;
|
||||
|
||||
private final String signature;
|
||||
|
||||
private final Map<String, Object> header;
|
||||
|
||||
private final Map<String, Object> claims;
|
||||
|
||||
Token(String encoded) {
|
||||
this.encoded = encoded;
|
||||
int firstPeriod = encoded.indexOf('.');
|
||||
int lastPeriod = encoded.lastIndexOf('.');
|
||||
if (firstPeriod <= 0 || lastPeriod <= firstPeriod) {
|
||||
throw new CloudFoundryAuthorizationException(
|
||||
CloudFoundryAuthorizationException.Reason.INVALID_TOKEN,
|
||||
"JWT must have header, body and signature");
|
||||
}
|
||||
this.header = parseJson(encoded.substring(0, firstPeriod));
|
||||
this.claims = parseJson(encoded.substring(firstPeriod + 1, lastPeriod));
|
||||
this.signature = encoded.substring(lastPeriod + 1);
|
||||
if (!StringUtils.hasLength(this.signature)) {
|
||||
throw new CloudFoundryAuthorizationException(
|
||||
CloudFoundryAuthorizationException.Reason.INVALID_TOKEN,
|
||||
"Token must have non-empty crypto segment");
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Object> parseJson(String base64) {
|
||||
try {
|
||||
byte[] bytes = Base64Utils.decodeFromUrlSafeString(base64);
|
||||
return JsonParserFactory.getJsonParser().parseMap(new String(bytes, UTF_8));
|
||||
}
|
||||
catch (RuntimeException ex) {
|
||||
throw new CloudFoundryAuthorizationException(
|
||||
CloudFoundryAuthorizationException.Reason.INVALID_TOKEN,
|
||||
"Token could not be parsed", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] getContent() {
|
||||
return this.encoded.substring(0, this.encoded.lastIndexOf(".")).getBytes();
|
||||
}
|
||||
|
||||
public byte[] getSignature() {
|
||||
return Base64Utils.decodeFromUrlSafeString(this.signature);
|
||||
}
|
||||
|
||||
public String getSignatureAlgorithm() {
|
||||
return getRequired(this.header, "alg", String.class);
|
||||
}
|
||||
|
||||
public String getIssuer() {
|
||||
return getRequired(this.claims, "iss", String.class);
|
||||
}
|
||||
|
||||
public long getExpiry() {
|
||||
return getRequired(this.claims, "exp", Integer.class).longValue();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<String> getScope() {
|
||||
return getRequired(this.claims, "scope", List.class);
|
||||
}
|
||||
|
||||
public String getKeyId() {
|
||||
return getRequired(this.header, "kid", String.class);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T getRequired(Map<String, Object> map, String key, Class<T> type) {
|
||||
Object value = map.get(key);
|
||||
if (value == null) {
|
||||
throw new CloudFoundryAuthorizationException(
|
||||
CloudFoundryAuthorizationException.Reason.INVALID_TOKEN,
|
||||
"Unable to get value from key " + key);
|
||||
}
|
||||
if (!type.isInstance(value)) {
|
||||
throw new CloudFoundryAuthorizationException(
|
||||
CloudFoundryAuthorizationException.Reason.INVALID_TOKEN,
|
||||
"Unexpected value type from key " + key + " value " + value);
|
||||
}
|
||||
return (T) value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.encoded;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,141 +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.security.GeneralSecurityException;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PublicKey;
|
||||
import java.security.Signature;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.boot.actuate.cloudfoundry.CloudFoundryAuthorizationException.Reason;
|
||||
import org.springframework.util.Base64Utils;
|
||||
|
||||
/**
|
||||
* Validator used to ensure that a signed {@link Token} has not been tampered with.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
class TokenValidator {
|
||||
|
||||
private final CloudFoundrySecurityService securityService;
|
||||
|
||||
private Map<String, String> tokenKeys;
|
||||
|
||||
TokenValidator(CloudFoundrySecurityService cloudFoundrySecurityService) {
|
||||
this.securityService = cloudFoundrySecurityService;
|
||||
}
|
||||
|
||||
public void validate(Token token) {
|
||||
validateAlgorithm(token);
|
||||
validateKeyIdAndSignature(token);
|
||||
validateExpiry(token);
|
||||
validateIssuer(token);
|
||||
validateAudience(token);
|
||||
}
|
||||
|
||||
private void validateAlgorithm(Token token) {
|
||||
String algorithm = token.getSignatureAlgorithm();
|
||||
if (algorithm == null) {
|
||||
throw new CloudFoundryAuthorizationException(Reason.INVALID_SIGNATURE,
|
||||
"Signing algorithm cannot be null");
|
||||
}
|
||||
if (!algorithm.equals("RS256")) {
|
||||
throw new CloudFoundryAuthorizationException(
|
||||
Reason.UNSUPPORTED_TOKEN_SIGNING_ALGORITHM,
|
||||
"Signing algorithm " + algorithm + " not supported");
|
||||
}
|
||||
}
|
||||
|
||||
private void validateKeyIdAndSignature(Token token) {
|
||||
String keyId = token.getKeyId();
|
||||
if (this.tokenKeys == null || !hasValidKeyId(keyId)) {
|
||||
this.tokenKeys = this.securityService.fetchTokenKeys();
|
||||
if (!hasValidKeyId(keyId)) {
|
||||
throw new CloudFoundryAuthorizationException(Reason.INVALID_KEY_ID,
|
||||
"Key Id present in token header does not match");
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasValidSignature(token, this.tokenKeys.get(keyId))) {
|
||||
throw new CloudFoundryAuthorizationException(Reason.INVALID_SIGNATURE,
|
||||
"RSA Signature did not match content");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasValidKeyId(String tokenKey) {
|
||||
for (String candidate : this.tokenKeys.keySet()) {
|
||||
if (tokenKey.equals(candidate)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean hasValidSignature(Token token, String key) {
|
||||
try {
|
||||
PublicKey publicKey = getPublicKey(key);
|
||||
Signature signature = Signature.getInstance("SHA256withRSA");
|
||||
signature.initVerify(publicKey);
|
||||
signature.update(token.getContent());
|
||||
return signature.verify(token.getSignature());
|
||||
}
|
||||
catch (GeneralSecurityException ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private PublicKey getPublicKey(String key)
|
||||
throws NoSuchAlgorithmException, InvalidKeySpecException {
|
||||
key = key.replace("-----BEGIN PUBLIC KEY-----\n", "");
|
||||
key = key.replace("-----END PUBLIC KEY-----", "");
|
||||
key = key.trim().replace("\n", "");
|
||||
byte[] bytes = Base64Utils.decodeFromString(key);
|
||||
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
|
||||
return KeyFactory.getInstance("RSA").generatePublic(keySpec);
|
||||
}
|
||||
|
||||
private void validateExpiry(Token token) {
|
||||
long currentTime = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis());
|
||||
if (currentTime > token.getExpiry()) {
|
||||
throw new CloudFoundryAuthorizationException(Reason.TOKEN_EXPIRED,
|
||||
"Token expired");
|
||||
}
|
||||
}
|
||||
|
||||
private void validateIssuer(Token token) {
|
||||
String uaaUrl = this.securityService.getUaaUrl();
|
||||
String issuerUri = String.format("%s/oauth/token", uaaUrl);
|
||||
if (!issuerUri.equals(token.getIssuer())) {
|
||||
throw new CloudFoundryAuthorizationException(Reason.INVALID_ISSUER,
|
||||
"Token issuer does not match " + uaaUrl + "/oauth/token");
|
||||
}
|
||||
}
|
||||
|
||||
private void validateAudience(Token token) {
|
||||
if (!token.getScope().contains("actuator.read")) {
|
||||
throw new CloudFoundryAuthorizationException(Reason.INVALID_AUDIENCE,
|
||||
"Token does not have audience actuator");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,14 +14,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.endpoint;
|
||||
package org.springframework.boot.actuate.context;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.boot.endpoint.Endpoint;
|
||||
import org.springframework.boot.endpoint.WriteOperation;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.WriteOperation;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
@@ -32,6 +32,7 @@ import org.springframework.context.ConfigurableApplicationContext;
|
||||
* @author Dave Syer
|
||||
* @author Christian Dupuis
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Endpoint(id = "shutdown", enabledByDefault = false)
|
||||
public class ShutdownEndpoint implements ApplicationContextAware {
|
||||
@@ -15,6 +15,6 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Auto-configuration for metrics.
|
||||
* Actuator support relating to Spring Context.
|
||||
*/
|
||||
package org.springframework.boot.actuate.autoconfigure.metrics;
|
||||
package org.springframework.boot.actuate.context;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.endpoint;
|
||||
package org.springframework.boot.actuate.context.properties;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@@ -40,10 +40,11 @@ import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
|
||||
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.boot.actuate.endpoint.Sanitizer;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
||||
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;
|
||||
@@ -62,6 +63,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Christian Dupuis
|
||||
* @author Dave Syer
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Endpoint(id = "configprops")
|
||||
@ConfigurationProperties("endpoints.configprops")
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Actuator support relating to external configuration properties.
|
||||
*/
|
||||
package org.springframework.boot.actuate.context.properties;
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2016 the original author or authors.
|
||||
* 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.
|
||||
@@ -14,12 +14,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.health;
|
||||
package org.springframework.boot.actuate.couchbase;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.couchbase.client.java.util.features.Version;
|
||||
|
||||
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.data.couchbase.core.CouchbaseOperations;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -28,7 +31,7 @@ import org.springframework.util.StringUtils;
|
||||
* {@link HealthIndicator} for Couchbase.
|
||||
*
|
||||
* @author Eddú Meléndez
|
||||
* @since 1.4.0
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class CouchbaseHealthIndicator extends AbstractHealthIndicator {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2016 the original author or authors.
|
||||
* 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.
|
||||
@@ -14,43 +14,68 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.health;
|
||||
package org.springframework.boot.actuate.elasticsearch;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest;
|
||||
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.client.Requests;
|
||||
|
||||
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* {@link HealthIndicator} for an Elasticsearch cluster.
|
||||
*
|
||||
* @author Binwei Yang
|
||||
* @author Andy Wilkinson
|
||||
* @since 1.3.0
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class ElasticsearchHealthIndicator extends AbstractHealthIndicator {
|
||||
|
||||
private static final String[] allIndices = { "_all" };
|
||||
private static final String[] ALL_INDICES = { "_all" };
|
||||
|
||||
private final Client client;
|
||||
|
||||
private final ElasticsearchHealthIndicatorProperties properties;
|
||||
private final String[] indices;
|
||||
|
||||
public ElasticsearchHealthIndicator(Client client,
|
||||
ElasticsearchHealthIndicatorProperties properties) {
|
||||
private final long responseTimeout;
|
||||
|
||||
/**
|
||||
* Create a new {@link ElasticsearchHealthIndicator} instance.
|
||||
* @param client the Elasticsearch client
|
||||
* @param responseTimeout the request timeout in milliseconds
|
||||
* @param indices the indices to check
|
||||
*/
|
||||
public ElasticsearchHealthIndicator(Client client, long responseTimeout,
|
||||
List<String> indices) {
|
||||
this(client, responseTimeout, (indices == null ? (String[]) null
|
||||
: indices.toArray(new String[indices.size()])));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link ElasticsearchHealthIndicator} instance.
|
||||
* @param client the Elasticsearch client
|
||||
* @param responseTimeout the request timeout in milliseconds
|
||||
* @param indices the indices to check
|
||||
*/
|
||||
public ElasticsearchHealthIndicator(Client client, long responseTimeout,
|
||||
String... indices) {
|
||||
this.client = client;
|
||||
this.properties = properties;
|
||||
this.responseTimeout = responseTimeout;
|
||||
this.indices = indices;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doHealthCheck(Health.Builder builder) throws Exception {
|
||||
List<String> indices = this.properties.getIndices();
|
||||
ClusterHealthResponse response = this.client.admin().cluster()
|
||||
.health(Requests.clusterHealthRequest(indices.isEmpty() ? allIndices
|
||||
: indices.toArray(new String[indices.size()])))
|
||||
.actionGet(this.properties.getResponseTimeout());
|
||||
|
||||
ClusterHealthRequest request = Requests.clusterHealthRequest(
|
||||
ObjectUtils.isEmpty(this.indices) ? ALL_INDICES : this.indices);
|
||||
ClusterHealthResponse response = this.client.admin().cluster().health(request)
|
||||
.actionGet(this.responseTimeout);
|
||||
switch (response.getStatus()) {
|
||||
case GREEN:
|
||||
case YELLOW:
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2016 the original author or authors.
|
||||
* 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.
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.health;
|
||||
package org.springframework.boot.actuate.elasticsearch;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
@@ -23,11 +23,15 @@ import io.searchbox.client.JestClient;
|
||||
import io.searchbox.client.JestResult;
|
||||
import io.searchbox.indices.Stats;
|
||||
|
||||
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
|
||||
/**
|
||||
* {@link HealthIndicator} for Elasticsearch using a {@link JestClient}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.4.0
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class ElasticsearchJestHealthIndicator extends AbstractHealthIndicator {
|
||||
|
||||
@@ -1,196 +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.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
|
||||
|
||||
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.endpoint.Endpoint;
|
||||
import org.springframework.boot.endpoint.ReadOperation;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link Endpoint} to expose the {@link ConditionEvaluationReport}.
|
||||
*
|
||||
* @author Greg Turnquist
|
||||
* @author Phillip Webb
|
||||
* @author Dave Syer
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@Endpoint(id = "autoconfig")
|
||||
public class AutoConfigurationReportEndpoint {
|
||||
|
||||
private final ConditionEvaluationReport conditionEvaluationReport;
|
||||
|
||||
public AutoConfigurationReportEndpoint(
|
||||
ConditionEvaluationReport conditionEvaluationReport) {
|
||||
this.conditionEvaluationReport = conditionEvaluationReport;
|
||||
}
|
||||
|
||||
@ReadOperation
|
||||
public Report getEvaluationReport() {
|
||||
return new Report(this.conditionEvaluationReport);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapts {@link ConditionEvaluationReport} to a JSON friendly structure.
|
||||
*/
|
||||
@JsonPropertyOrder({ "positiveMatches", "negativeMatches", "exclusions",
|
||||
"unconditionalClasses" })
|
||||
@JsonInclude(Include.NON_EMPTY)
|
||||
public static class Report {
|
||||
|
||||
private final MultiValueMap<String, MessageAndCondition> positiveMatches;
|
||||
|
||||
private final Map<String, MessageAndConditions> negativeMatches;
|
||||
|
||||
private final List<String> exclusions;
|
||||
|
||||
private final Set<String> unconditionalClasses;
|
||||
|
||||
private final Report parent;
|
||||
|
||||
public Report(ConditionEvaluationReport report) {
|
||||
this.positiveMatches = new LinkedMultiValueMap<>();
|
||||
this.negativeMatches = new LinkedHashMap<>();
|
||||
this.exclusions = report.getExclusions();
|
||||
this.unconditionalClasses = report.getUnconditionalClasses();
|
||||
for (Map.Entry<String, ConditionAndOutcomes> entry : report
|
||||
.getConditionAndOutcomesBySource().entrySet()) {
|
||||
if (entry.getValue().isFullMatch()) {
|
||||
add(this.positiveMatches, entry.getKey(), entry.getValue());
|
||||
}
|
||||
else {
|
||||
add(this.negativeMatches, entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
boolean hasParent = report.getParent() != null;
|
||||
this.parent = (hasParent ? new Report(report.getParent()) : null);
|
||||
}
|
||||
|
||||
private void add(Map<String, MessageAndConditions> map, String source,
|
||||
ConditionAndOutcomes conditionAndOutcomes) {
|
||||
String name = ClassUtils.getShortName(source);
|
||||
map.put(name, new MessageAndConditions(conditionAndOutcomes));
|
||||
}
|
||||
|
||||
private void add(MultiValueMap<String, MessageAndCondition> map, String source,
|
||||
ConditionAndOutcomes conditionAndOutcomes) {
|
||||
String name = ClassUtils.getShortName(source);
|
||||
for (ConditionAndOutcome conditionAndOutcome : conditionAndOutcomes) {
|
||||
map.add(name, new MessageAndCondition(conditionAndOutcome));
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, List<MessageAndCondition>> getPositiveMatches() {
|
||||
return this.positiveMatches;
|
||||
}
|
||||
|
||||
public Map<String, MessageAndConditions> getNegativeMatches() {
|
||||
return this.negativeMatches;
|
||||
}
|
||||
|
||||
public List<String> getExclusions() {
|
||||
return this.exclusions;
|
||||
}
|
||||
|
||||
public Set<String> getUnconditionalClasses() {
|
||||
return this.unconditionalClasses;
|
||||
}
|
||||
|
||||
public Report getParent() {
|
||||
return this.parent;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapts {@link ConditionAndOutcomes} to a JSON friendly structure.
|
||||
*/
|
||||
@JsonPropertyOrder({ "notMatched", "matched" })
|
||||
public static class MessageAndConditions {
|
||||
|
||||
private final List<MessageAndCondition> notMatched = new ArrayList<>();
|
||||
|
||||
private final List<MessageAndCondition> matched = new ArrayList<>();
|
||||
|
||||
public MessageAndConditions(ConditionAndOutcomes conditionAndOutcomes) {
|
||||
for (ConditionAndOutcome conditionAndOutcome : conditionAndOutcomes) {
|
||||
List<MessageAndCondition> target = conditionAndOutcome.getOutcome()
|
||||
.isMatch() ? this.matched : this.notMatched;
|
||||
target.add(new MessageAndCondition(conditionAndOutcome));
|
||||
}
|
||||
}
|
||||
|
||||
public List<MessageAndCondition> getNotMatched() {
|
||||
return this.notMatched;
|
||||
}
|
||||
|
||||
public List<MessageAndCondition> getMatched() {
|
||||
return this.matched;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapts {@link ConditionAndOutcome} to a JSON friendly structure.
|
||||
*/
|
||||
@JsonPropertyOrder({ "condition", "message" })
|
||||
public static class MessageAndCondition {
|
||||
|
||||
private final String condition;
|
||||
|
||||
private final String message;
|
||||
|
||||
public MessageAndCondition(ConditionAndOutcome conditionAndOutcome) {
|
||||
Condition condition = conditionAndOutcome.getCondition();
|
||||
ConditionOutcome outcome = conditionAndOutcome.getOutcome();
|
||||
this.condition = ClassUtils.getShortName(condition.getClass());
|
||||
if (StringUtils.hasLength(outcome.getMessage())) {
|
||||
this.message = outcome.getMessage();
|
||||
}
|
||||
else {
|
||||
this.message = (outcome.isMatch() ? "matched" : "did not match");
|
||||
}
|
||||
}
|
||||
|
||||
public String getCondition() {
|
||||
return this.condition;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return this.message;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,24 +14,25 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.endpoint.infrastructure;
|
||||
package org.springframework.boot.actuate.endpoint;
|
||||
|
||||
import org.springframework.boot.endpoint.web.mvc.WebEndpointServletHandlerMapping;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Callback for customizing the {@link WebEndpointServletHandlerMapping} at configuration
|
||||
* time.
|
||||
* Discovers endpoints and provides an {@link EndpointInfo} for each of them.
|
||||
*
|
||||
* @param <T> the type of the operation
|
||||
* @author Andy Wilkinson
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface WebEndpointHandlerMappingCustomizer {
|
||||
public interface EndpointDiscoverer<T extends Operation> {
|
||||
|
||||
/**
|
||||
* Customize the given {@code mapping}.
|
||||
* @param mapping the mapping to customize
|
||||
* Perform endpoint discovery.
|
||||
* @return the discovered endpoints
|
||||
*/
|
||||
void customize(WebEndpointServletHandlerMapping mapping);
|
||||
Collection<EndpointInfo<T>> discoverEndpoints();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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.Collection;
|
||||
|
||||
/**
|
||||
* Information describing an endpoint.
|
||||
*
|
||||
* @param <T> the type of the endpoint's operations
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class EndpointInfo<T extends Operation> {
|
||||
|
||||
private final String id;
|
||||
|
||||
private final boolean enabledByDefault;
|
||||
|
||||
private final Collection<T> operations;
|
||||
|
||||
/**
|
||||
* Creates a new {@code EndpointInfo} describing an endpoint with the given {@code id}
|
||||
* and {@code operations}.
|
||||
* @param id the id of the endpoint
|
||||
* @param enabledByDefault whether or not the endpoint is enabled by default
|
||||
* @param operations the operations of the endpoint
|
||||
*/
|
||||
public EndpointInfo(String id, boolean enabledByDefault, Collection<T> operations) {
|
||||
this.id = id;
|
||||
this.enabledByDefault = enabledByDefault;
|
||||
this.operations = operations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the id of the endpoint.
|
||||
* @return the id
|
||||
*/
|
||||
public String getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not this endpoint is enabled by default.
|
||||
* @return {@code true} if it is enabled by default, otherwise {@code false}
|
||||
*/
|
||||
public boolean isEnabledByDefault() {
|
||||
return this.enabledByDefault;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the operations of the endpoint.
|
||||
* @return the operations
|
||||
*/
|
||||
public Collection<T> getOperations() {
|
||||
return this.operations;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* An operation on an endpoint.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class Operation {
|
||||
|
||||
private final OperationType type;
|
||||
|
||||
private final OperationInvoker invoker;
|
||||
|
||||
private final boolean blocking;
|
||||
|
||||
/**
|
||||
* Creates a new {@code EndpointOperation} for an operation of the given {@code type}.
|
||||
* The operation can be performed using the given {@code operationInvoker}.
|
||||
* @param type the type of the operation
|
||||
* @param operationInvoker used to perform the operation
|
||||
* @param blocking whether or not this is a blocking operation
|
||||
*/
|
||||
public Operation(OperationType type, OperationInvoker operationInvoker,
|
||||
boolean blocking) {
|
||||
this.type = type;
|
||||
this.invoker = operationInvoker;
|
||||
this.blocking = blocking;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link OperationType type} of the operation.
|
||||
* @return the type
|
||||
*/
|
||||
public OperationType getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code OperationInvoker} that can be used to invoke this endpoint
|
||||
* operation.
|
||||
* @return the operation invoker
|
||||
*/
|
||||
public OperationInvoker getInvoker() {
|
||||
return this.invoker;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not this is a blocking operation.
|
||||
*
|
||||
* @return {@code true} if it is a blocking operation, otherwise {@code false}.
|
||||
*/
|
||||
public boolean isBlocking() {
|
||||
return this.blocking;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,31 +14,24 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure;
|
||||
package org.springframework.boot.actuate.endpoint;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Enumeration of management context types.
|
||||
* An {@code OperationInvoker} is used to invoke an operation on an endpoint.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public enum ManagementContextType {
|
||||
@FunctionalInterface
|
||||
public interface OperationInvoker {
|
||||
|
||||
/**
|
||||
* The management context is the same as the main application context.
|
||||
* Invoke the underlying operation using the given {@code arguments}.
|
||||
* @param arguments the arguments to pass to the operation
|
||||
* @return the result of the operation, may be {@code null}
|
||||
*/
|
||||
SAME,
|
||||
|
||||
/**
|
||||
* The management context is a separate context that is a child of the main
|
||||
* application context.
|
||||
*/
|
||||
CHILD,
|
||||
|
||||
/**
|
||||
* The management context can be either the same as the main application context or a
|
||||
* child of the main application context.
|
||||
*/
|
||||
ANY
|
||||
Object invoke(Map<String, Object> arguments);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* An {@code OperationParameterMapper} is used to map parameters to the required type when
|
||||
* invoking an endpoint.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface OperationParameterMapper {
|
||||
|
||||
/**
|
||||
* Map the specified {@code input} parameter to the given {@code parameterType}.
|
||||
* @param input a parameter value
|
||||
* @param parameterType the required type of the parameter
|
||||
* @return a value suitable for that parameter
|
||||
* @param <T> the actual type of the parameter
|
||||
* @throws ParameterMappingException when a mapping failure occurs
|
||||
*/
|
||||
<T> T mapParameter(Object input, Class<T> parameterType);
|
||||
|
||||
}
|
||||
@@ -14,17 +14,29 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
package org.springframework.boot.actuate.endpoint;
|
||||
|
||||
/**
|
||||
* Configuration class used to enable configuration of a child management context.
|
||||
* An enumeration of the different types of operation supported by an endpoint.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@EnableManagementContext(ManagementContextType.CHILD)
|
||||
class EnableChildManagementContextConfiguration {
|
||||
public enum OperationType {
|
||||
|
||||
/**
|
||||
* A read operation.
|
||||
*/
|
||||
READ,
|
||||
|
||||
/**
|
||||
* A write operation.
|
||||
*/
|
||||
WRITE,
|
||||
|
||||
/**
|
||||
* A delete operation.
|
||||
*/
|
||||
DELETE
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* A {@code ParameterMappingException} is thrown when a failure occurs during
|
||||
* {@link OperationParameterMapper#mapParameter(Object, Class) operation parameter
|
||||
* mapping}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class ParameterMappingException extends RuntimeException {
|
||||
|
||||
private final Object input;
|
||||
|
||||
private final Class<?> type;
|
||||
|
||||
/**
|
||||
* Creates a new {@code ParameterMappingException} for a failure that occurred when
|
||||
* trying to map the given {@code input} to the given {@code type}.
|
||||
*
|
||||
* @param input the input that was being mapped
|
||||
* @param type the type that was being mapped to
|
||||
* @param cause the cause of the mapping failure
|
||||
*/
|
||||
public ParameterMappingException(Object input, Class<?> type, Throwable cause) {
|
||||
super("Failed to map " + input + " of type " + input.getClass() + " to type "
|
||||
+ type, cause);
|
||||
this.input = input;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the input that was to be mapped.
|
||||
* @return the input
|
||||
*/
|
||||
public Object getInput() {
|
||||
return this.input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type to be mapped to.
|
||||
* @return the type
|
||||
*/
|
||||
public Class<?> getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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.lang.reflect.Method;
|
||||
import java.lang.reflect.Parameter;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* An {@code OperationInvoker} that invokes an operation using reflection.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class ReflectiveOperationInvoker implements OperationInvoker {
|
||||
|
||||
private final OperationParameterMapper parameterMapper;
|
||||
|
||||
private final Object target;
|
||||
|
||||
private final Method method;
|
||||
|
||||
/**
|
||||
* Creates a new {code ReflectiveOperationInvoker} that will invoke the given
|
||||
* {@code method} on the given {@code target}. The given {@code parameterMapper} will
|
||||
* be used to map parameters to the required types.
|
||||
* @param parameterMapper the parameter mapper
|
||||
* @param target the target of the reflective call
|
||||
* @param method the method to call
|
||||
*/
|
||||
public ReflectiveOperationInvoker(OperationParameterMapper parameterMapper,
|
||||
Object target, Method method) {
|
||||
this.parameterMapper = parameterMapper;
|
||||
this.target = target;
|
||||
ReflectionUtils.makeAccessible(method);
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(Map<String, Object> arguments) {
|
||||
return ReflectionUtils.invokeMethod(this.method, this.target,
|
||||
resolveArguments(arguments));
|
||||
}
|
||||
|
||||
private Object[] resolveArguments(Map<String, Object> arguments) {
|
||||
return Stream.of(this.method.getParameters())
|
||||
.map((parameter) -> resolveArgument(parameter, arguments))
|
||||
.collect(Collectors.collectingAndThen(Collectors.toList(),
|
||||
(list) -> list.toArray(new Object[list.size()])));
|
||||
}
|
||||
|
||||
private Object resolveArgument(Parameter parameter, Map<String, Object> arguments) {
|
||||
Object resolved = arguments.get(parameter.getName());
|
||||
return this.parameterMapper.mapParameter(resolved, parameter.getType());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,151 +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.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.beans.BeansException;
|
||||
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;
|
||||
import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;
|
||||
import org.springframework.web.servlet.handler.AbstractUrlHandlerMapping;
|
||||
|
||||
/**
|
||||
* {@link Endpoint} to expose Spring MVC mappings.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@Endpoint(id = "mappings")
|
||||
public class RequestMappingEndpoint implements ApplicationContextAware {
|
||||
|
||||
private List<AbstractUrlHandlerMapping> handlerMappings = Collections.emptyList();
|
||||
|
||||
private List<AbstractHandlerMethodMapping<?>> methodMappings = Collections
|
||||
.emptyList();
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext)
|
||||
throws BeansException {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the handler mappings.
|
||||
* @param handlerMappings the handler mappings
|
||||
*/
|
||||
public void setHandlerMappings(List<AbstractUrlHandlerMapping> handlerMappings) {
|
||||
this.handlerMappings = handlerMappings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the method mappings.
|
||||
* @param methodMappings the method mappings
|
||||
*/
|
||||
public void setMethodMappings(List<AbstractHandlerMethodMapping<?>> methodMappings) {
|
||||
this.methodMappings = methodMappings;
|
||||
}
|
||||
|
||||
@ReadOperation
|
||||
public Map<String, Object> mappings() {
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
extractHandlerMappings(this.handlerMappings, result);
|
||||
extractHandlerMappings(this.applicationContext, result);
|
||||
extractMethodMappings(this.methodMappings, result);
|
||||
extractMethodMappings(this.applicationContext, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
protected void extractMethodMappings(ApplicationContext applicationContext,
|
||||
Map<String, Object> result) {
|
||||
if (applicationContext != null) {
|
||||
for (Entry<String, AbstractHandlerMethodMapping> bean : applicationContext
|
||||
.getBeansOfType(AbstractHandlerMethodMapping.class).entrySet()) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<?, HandlerMethod> methods = bean.getValue().getHandlerMethods();
|
||||
for (Entry<?, HandlerMethod> method : methods.entrySet()) {
|
||||
Map<String, String> map = new LinkedHashMap<>();
|
||||
map.put("bean", bean.getKey());
|
||||
map.put("method", method.getValue().toString());
|
||||
result.put(method.getKey().toString(), map);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void extractHandlerMappings(ApplicationContext applicationContext,
|
||||
Map<String, Object> result) {
|
||||
if (applicationContext != null) {
|
||||
Map<String, AbstractUrlHandlerMapping> mappings = applicationContext
|
||||
.getBeansOfType(AbstractUrlHandlerMapping.class);
|
||||
for (Entry<String, AbstractUrlHandlerMapping> mapping : mappings.entrySet()) {
|
||||
Map<String, Object> handlers = getHandlerMap(mapping.getValue());
|
||||
for (Entry<String, Object> handler : handlers.entrySet()) {
|
||||
result.put(handler.getKey(),
|
||||
Collections.singletonMap("bean", mapping.getKey()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Object> getHandlerMap(AbstractUrlHandlerMapping mapping) {
|
||||
if (AopUtils.isCglibProxy(mapping)) {
|
||||
// If the AbstractUrlHandlerMapping is a cglib proxy we can't call
|
||||
// the final getHandlerMap() method.
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
return mapping.getHandlerMap();
|
||||
}
|
||||
|
||||
protected void extractHandlerMappings(
|
||||
Collection<AbstractUrlHandlerMapping> handlerMappings,
|
||||
Map<String, Object> result) {
|
||||
for (AbstractUrlHandlerMapping mapping : handlerMappings) {
|
||||
Map<String, Object> handlers = mapping.getHandlerMap();
|
||||
for (Map.Entry<String, Object> entry : handlers.entrySet()) {
|
||||
Class<? extends Object> handlerClass = entry.getValue().getClass();
|
||||
result.put(entry.getKey(),
|
||||
Collections.singletonMap("type", handlerClass.getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void extractMethodMappings(
|
||||
Collection<AbstractHandlerMethodMapping<?>> methodMappings,
|
||||
Map<String, Object> result) {
|
||||
for (AbstractHandlerMethodMapping<?> mapping : methodMappings) {
|
||||
Map<?, HandlerMethod> methods = mapping.getHandlerMethods();
|
||||
for (Map.Entry<?, HandlerMethod> entry : methods.entrySet()) {
|
||||
result.put(String.valueOf(entry.getKey()), Collections
|
||||
.singletonMap("method", String.valueOf(entry.getValue())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2016 the original author or authors.
|
||||
* 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.
|
||||
@@ -21,25 +21,27 @@ import java.util.regex.Pattern;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Internal strategy used to sanitize potentially sensitive keys.
|
||||
* Strategy that be be used by endpoint implementations to sanitize potentially sensitive
|
||||
* keys.
|
||||
*
|
||||
* @author Christian Dupuis
|
||||
* @author Toshiaki Maki
|
||||
* @author Phillip Webb
|
||||
* @author Nicolas Lejeune
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.0.0
|
||||
*/
|
||||
class Sanitizer {
|
||||
public class Sanitizer {
|
||||
|
||||
private static final String[] REGEX_PARTS = { "*", "$", "^", "+" };
|
||||
|
||||
private Pattern[] keysToSanitize;
|
||||
|
||||
Sanitizer() {
|
||||
public Sanitizer() {
|
||||
this("password", "secret", "key", "token", ".*credentials.*", "vcap_services");
|
||||
}
|
||||
|
||||
Sanitizer(String... keysToSanitize) {
|
||||
public Sanitizer(String... keysToSanitize) {
|
||||
setKeysToSanitize(keysToSanitize);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,410 @@
|
||||
/*
|
||||
* 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.annotation;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.boot.actuate.endpoint.EndpointDiscoverer;
|
||||
import org.springframework.boot.actuate.endpoint.EndpointInfo;
|
||||
import org.springframework.boot.actuate.endpoint.Operation;
|
||||
import org.springframework.boot.actuate.endpoint.OperationType;
|
||||
import org.springframework.boot.actuate.endpoint.cache.CachingConfiguration;
|
||||
import org.springframework.boot.actuate.endpoint.cache.CachingConfigurationFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.MethodIntrospector;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* A base {@link EndpointDiscoverer} implementation that discovers {@link Endpoint} beans
|
||||
* in an application context.
|
||||
*
|
||||
* @param <T> the type of the operation
|
||||
* @param <K> the type of the operation key
|
||||
* @author Andy Wilkinson
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public abstract class AnnotationEndpointDiscoverer<T extends Operation, K>
|
||||
implements EndpointDiscoverer<T> {
|
||||
|
||||
private final ApplicationContext applicationContext;
|
||||
|
||||
private final EndpointOperationFactory<T> operationFactory;
|
||||
|
||||
private final Function<T, K> operationKeyFactory;
|
||||
|
||||
private final CachingConfigurationFactory cachingConfigurationFactory;
|
||||
|
||||
protected AnnotationEndpointDiscoverer(ApplicationContext applicationContext,
|
||||
EndpointOperationFactory<T> operationFactory,
|
||||
Function<T, K> operationKeyFactory,
|
||||
CachingConfigurationFactory cachingConfigurationFactory) {
|
||||
this.applicationContext = applicationContext;
|
||||
this.operationFactory = operationFactory;
|
||||
this.operationKeyFactory = operationKeyFactory;
|
||||
this.cachingConfigurationFactory = cachingConfigurationFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform endpoint discovery, including discovery and merging of extensions.
|
||||
* @param extensionType the annotation type of the extension
|
||||
* @param exposure the {@link EndpointExposure} that should be considered
|
||||
* @return the list of {@link EndpointInfo EndpointInfos} that describes the
|
||||
* discovered endpoints matching the specified {@link EndpointExposure}
|
||||
*/
|
||||
protected Collection<EndpointInfoDescriptor<T, K>> discoverEndpoints(
|
||||
Class<? extends Annotation> extensionType, EndpointExposure exposure) {
|
||||
Map<Class<?>, EndpointInfo<T>> endpoints = discoverEndpoints(exposure);
|
||||
Map<Class<?>, EndpointExtensionInfo<T>> extensions = discoverExtensions(endpoints,
|
||||
extensionType, exposure);
|
||||
Collection<EndpointInfoDescriptor<T, K>> result = new ArrayList<>();
|
||||
endpoints.forEach((endpointClass, endpointInfo) -> {
|
||||
EndpointExtensionInfo<T> extension = extensions.remove(endpointClass);
|
||||
result.add(createDescriptor(endpointClass, endpointInfo, extension));
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
private Map<Class<?>, EndpointInfo<T>> discoverEndpoints(EndpointExposure exposure) {
|
||||
String[] beanNames = BeanFactoryUtils.beanNamesForAnnotationIncludingAncestors(
|
||||
this.applicationContext, Endpoint.class);
|
||||
Map<Class<?>, EndpointInfo<T>> endpoints = new LinkedHashMap<>();
|
||||
Map<String, EndpointInfo<T>> endpointsById = new LinkedHashMap<>();
|
||||
for (String beanName : beanNames) {
|
||||
Class<?> beanType = this.applicationContext.getType(beanName);
|
||||
AnnotationAttributes attributes = AnnotatedElementUtils
|
||||
.findMergedAnnotationAttributes(beanType, Endpoint.class, true, true);
|
||||
if (isExposedOver(attributes, exposure)) {
|
||||
EndpointInfo<T> info = createEndpointInfo(beanName, beanType, attributes);
|
||||
EndpointInfo<T> previous = endpointsById.putIfAbsent(info.getId(), info);
|
||||
Assert.state(previous == null, () -> "Found two endpoints with the id '"
|
||||
+ info.getId() + "': " + info + " and " + previous);
|
||||
endpoints.put(beanType, info);
|
||||
}
|
||||
}
|
||||
return endpoints;
|
||||
}
|
||||
|
||||
private EndpointInfo<T> createEndpointInfo(String beanName, Class<?> beanType,
|
||||
AnnotationAttributes attributes) {
|
||||
String id = attributes.getString("id");
|
||||
boolean enabledByDefault = attributes.getBoolean("enabledByDefault");
|
||||
Map<Method, T> operations = discoverOperations(id, beanName, beanType);
|
||||
return new EndpointInfo<>(id, enabledByDefault, operations.values());
|
||||
}
|
||||
|
||||
private Map<Class<?>, EndpointExtensionInfo<T>> discoverExtensions(
|
||||
Map<Class<?>, EndpointInfo<T>> endpoints,
|
||||
Class<? extends Annotation> extensionType, EndpointExposure exposure) {
|
||||
if (extensionType == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
String[] beanNames = BeanFactoryUtils.beanNamesForAnnotationIncludingAncestors(
|
||||
this.applicationContext, extensionType);
|
||||
Map<Class<?>, EndpointExtensionInfo<T>> extensions = new HashMap<>();
|
||||
for (String beanName : beanNames) {
|
||||
Class<?> beanType = this.applicationContext.getType(beanName);
|
||||
Class<?> endpointType = getEndpointType(extensionType, beanType);
|
||||
AnnotationAttributes endpointAttributes = AnnotatedElementUtils
|
||||
.getMergedAnnotationAttributes(endpointType, Endpoint.class);
|
||||
Assert.state(isExposedOver(endpointAttributes, exposure),
|
||||
"Invalid extension " + beanType.getName() + "': endpoint '"
|
||||
+ endpointType.getName()
|
||||
+ "' does not support such extension");
|
||||
EndpointInfo<T> info = getEndpointInfo(endpoints, beanType, endpointType);
|
||||
Map<Method, T> operations = discoverOperations(info.getId(), beanName,
|
||||
beanType);
|
||||
EndpointExtensionInfo<T> extension = new EndpointExtensionInfo<>(beanType,
|
||||
operations.values());
|
||||
EndpointExtensionInfo<T> previous = extensions.putIfAbsent(endpointType,
|
||||
extension);
|
||||
Assert.state(previous == null,
|
||||
() -> "Found two extensions for the same endpoint '"
|
||||
+ endpointType.getName() + "': "
|
||||
+ extension.getExtensionType().getName() + " and "
|
||||
+ previous.getExtensionType().getName());
|
||||
}
|
||||
return extensions;
|
||||
|
||||
}
|
||||
|
||||
private EndpointInfo<T> getEndpointInfo(Map<Class<?>, EndpointInfo<T>> endpoints,
|
||||
Class<?> beanType, Class<?> endpointClass) {
|
||||
EndpointInfo<T> endpoint = endpoints.get(endpointClass);
|
||||
Assert.state(endpoint != null, "Invalid extension '" + beanType.getName()
|
||||
+ "': no endpoint found with type '" + endpointClass.getName() + "'");
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
private Class<?> getEndpointType(Class<? extends Annotation> extensionType,
|
||||
Class<?> beanType) {
|
||||
AnnotationAttributes attributes = AnnotatedElementUtils
|
||||
.getMergedAnnotationAttributes(beanType, extensionType);
|
||||
return (Class<?>) attributes.get("endpoint");
|
||||
}
|
||||
|
||||
private EndpointInfoDescriptor<T, K> createDescriptor(Class<?> type,
|
||||
EndpointInfo<T> info, EndpointExtensionInfo<T> extension) {
|
||||
Map<OperationKey<K>, List<T>> operations = indexOperations(info.getId(), type,
|
||||
info.getOperations());
|
||||
if (extension != null) {
|
||||
operations.putAll(indexOperations(info.getId(), extension.getExtensionType(),
|
||||
extension.getOperations()));
|
||||
return new EndpointInfoDescriptor<>(mergeEndpoint(info, extension),
|
||||
operations);
|
||||
}
|
||||
return new EndpointInfoDescriptor<>(info, operations);
|
||||
}
|
||||
|
||||
private EndpointInfo<T> mergeEndpoint(EndpointInfo<T> endpoint,
|
||||
EndpointExtensionInfo<T> extension) {
|
||||
Map<K, T> operations = new HashMap<>();
|
||||
Consumer<T> consumer = (operation) -> operations
|
||||
.put(this.operationKeyFactory.apply(operation), operation);
|
||||
endpoint.getOperations().forEach(consumer);
|
||||
extension.getOperations().forEach(consumer);
|
||||
return new EndpointInfo<>(endpoint.getId(), endpoint.isEnabledByDefault(),
|
||||
operations.values());
|
||||
}
|
||||
|
||||
private Map<OperationKey<K>, List<T>> indexOperations(String endpointId,
|
||||
Class<?> target, Collection<T> operations) {
|
||||
LinkedMultiValueMap<OperationKey<K>, T> result = new LinkedMultiValueMap<>();
|
||||
operations.forEach((operation) -> {
|
||||
K key = this.operationKeyFactory.apply(operation);
|
||||
result.add(new OperationKey<>(endpointId, target, key), operation);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean isExposedOver(AnnotationAttributes attributes,
|
||||
EndpointExposure exposure) {
|
||||
if (exposure == null) {
|
||||
return true;
|
||||
}
|
||||
EndpointExposure[] supported = (EndpointExposure[]) attributes.get("exposure");
|
||||
return ObjectUtils.isEmpty(supported)
|
||||
|| ObjectUtils.containsElement(supported, exposure);
|
||||
}
|
||||
|
||||
private Map<Method, T> discoverOperations(String id, String name, Class<?> type) {
|
||||
return MethodIntrospector.selectMethods(type,
|
||||
(MethodIntrospector.MetadataLookup<T>) (
|
||||
method) -> createOperationIfPossible(id, name, method));
|
||||
}
|
||||
|
||||
private T createOperationIfPossible(String endpointId, String beanName,
|
||||
Method method) {
|
||||
T operation = createReadOperationIfPossible(endpointId, beanName, method);
|
||||
if (operation != null) {
|
||||
return operation;
|
||||
}
|
||||
operation = createWriteOperationIfPossible(endpointId, beanName, method);
|
||||
if (operation != null) {
|
||||
return operation;
|
||||
}
|
||||
return createDeleteOperationIfPossible(endpointId, beanName, method);
|
||||
}
|
||||
|
||||
private T createReadOperationIfPossible(String endpointId, String beanName,
|
||||
Method method) {
|
||||
return createOperationIfPossible(endpointId, beanName, method,
|
||||
ReadOperation.class, OperationType.READ);
|
||||
}
|
||||
|
||||
private T createWriteOperationIfPossible(String endpointId, String beanName,
|
||||
Method method) {
|
||||
return createOperationIfPossible(endpointId, beanName, method,
|
||||
WriteOperation.class, OperationType.WRITE);
|
||||
}
|
||||
|
||||
private T createDeleteOperationIfPossible(String endpointId, String beanName,
|
||||
Method method) {
|
||||
return createOperationIfPossible(endpointId, beanName, method,
|
||||
DeleteOperation.class, OperationType.DELETE);
|
||||
}
|
||||
|
||||
private T createOperationIfPossible(String endpointId, String beanName, Method method,
|
||||
Class<? extends Annotation> operationAnnotation,
|
||||
OperationType operationType) {
|
||||
AnnotationAttributes operationAttributes = AnnotatedElementUtils
|
||||
.getMergedAnnotationAttributes(method, operationAnnotation);
|
||||
if (operationAttributes == null) {
|
||||
return null;
|
||||
}
|
||||
CachingConfiguration cachingConfiguration = this.cachingConfigurationFactory
|
||||
.getCachingConfiguration(endpointId);
|
||||
return this.operationFactory.createOperation(endpointId, operationAttributes,
|
||||
this.applicationContext.getBean(beanName), method, operationType,
|
||||
determineTimeToLive(cachingConfiguration, operationType, method));
|
||||
}
|
||||
|
||||
private long determineTimeToLive(CachingConfiguration cachingConfiguration,
|
||||
OperationType operationType, Method method) {
|
||||
if (cachingConfiguration != null && cachingConfiguration.getTimeToLive() > 0
|
||||
&& operationType == OperationType.READ
|
||||
&& method.getParameters().length == 0) {
|
||||
return cachingConfiguration.getTimeToLive();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* An {@code EndpointOperationFactory} creates an {@link Operation} for an operation
|
||||
* on an endpoint.
|
||||
*
|
||||
* @param <T> the {@link Operation} type
|
||||
*/
|
||||
@FunctionalInterface
|
||||
protected interface EndpointOperationFactory<T extends Operation> {
|
||||
|
||||
/**
|
||||
* Creates an {@code EndpointOperation} for an operation on an endpoint.
|
||||
* @param endpointId the id of the endpoint
|
||||
* @param operationAttributes the annotation attributes for the operation
|
||||
* @param target the target that implements the operation
|
||||
* @param operationMethod the method on the bean that implements the operation
|
||||
* @param operationType the type of the operation
|
||||
* @param timeToLive the caching period in milliseconds
|
||||
* @return the operation info that describes the operation
|
||||
*/
|
||||
T createOperation(String endpointId, AnnotationAttributes operationAttributes,
|
||||
Object target, Method operationMethod, OperationType operationType,
|
||||
long timeToLive);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes a tech-specific extension of an endpoint.
|
||||
* @param <T> the type of the operation
|
||||
*/
|
||||
private static final class EndpointExtensionInfo<T extends Operation> {
|
||||
|
||||
private final Class<?> extensionType;
|
||||
|
||||
private final Collection<T> operations;
|
||||
|
||||
private EndpointExtensionInfo(Class<?> extensionType, Collection<T> operations) {
|
||||
this.extensionType = extensionType;
|
||||
this.operations = operations;
|
||||
}
|
||||
|
||||
private Class<?> getExtensionType() {
|
||||
return this.extensionType;
|
||||
}
|
||||
|
||||
private Collection<T> getOperations() {
|
||||
return this.operations;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes an {@link EndpointInfo endpoint} and whether or not it is valid.
|
||||
*
|
||||
* @param <T> the type of the operation
|
||||
* @param <K> the type of the operation key
|
||||
*/
|
||||
protected static class EndpointInfoDescriptor<T extends Operation, K> {
|
||||
|
||||
private final EndpointInfo<T> endpointInfo;
|
||||
|
||||
private final Map<OperationKey<K>, List<T>> operations;
|
||||
|
||||
protected EndpointInfoDescriptor(EndpointInfo<T> endpointInfo,
|
||||
Map<OperationKey<K>, List<T>> operations) {
|
||||
this.endpointInfo = endpointInfo;
|
||||
this.operations = operations;
|
||||
}
|
||||
|
||||
public EndpointInfo<T> getEndpointInfo() {
|
||||
return this.endpointInfo;
|
||||
}
|
||||
|
||||
public Map<OperationKey<K>, List<T>> findDuplicateOperations() {
|
||||
Map<OperationKey<K>, List<T>> duplicateOperations = new HashMap<>();
|
||||
this.operations.forEach((k, list) -> {
|
||||
if (list.size() > 1) {
|
||||
duplicateOperations.put(k, list);
|
||||
}
|
||||
});
|
||||
return duplicateOperations;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the key of an operation in the context of an operation's implementation.
|
||||
*
|
||||
* @param <K> the type of the key
|
||||
*/
|
||||
protected static final class OperationKey<K> {
|
||||
|
||||
private final String endpointId;
|
||||
|
||||
private final Class<?> endpointType;
|
||||
|
||||
private final K key;
|
||||
|
||||
public OperationKey(String endpointId, Class<?> endpointType, K key) {
|
||||
this.endpointId = endpointId;
|
||||
this.endpointType = endpointType;
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
OperationKey<?> other = (OperationKey<?>) o;
|
||||
Boolean result = true;
|
||||
result = result && this.endpointId.equals(other.endpointId);
|
||||
result = result && this.endpointType.equals(other.endpointType);
|
||||
result = result && this.key.equals(other.key);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = this.endpointId.hashCode();
|
||||
result = 31 * result + this.endpointType.hashCode();
|
||||
result = 31 * result + this.key.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure;
|
||||
package org.springframework.boot.actuate.endpoint.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
@@ -22,23 +22,23 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
* Enables the management context.
|
||||
* Identifies a method on an {@link Endpoint} as being a delete operation.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Import(ManagementContextConfigurationImportSelector.class)
|
||||
@interface EnableManagementContext {
|
||||
public @interface DeleteOperation {
|
||||
|
||||
/**
|
||||
* The management context type that should be enabled.
|
||||
* @return the management context type
|
||||
* The media type of the result of the operation.
|
||||
*
|
||||
* @return the media type
|
||||
*/
|
||||
ManagementContextType value();
|
||||
String[] produces() default {};
|
||||
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.health;
|
||||
package org.springframework.boot.actuate.endpoint.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
@@ -22,28 +22,37 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.boot.actuate.endpoint.EndpointDiscoverer;
|
||||
|
||||
/**
|
||||
* {@link Conditional} that checks whether or not a default health indicator is enabled.
|
||||
* Matches if the value of the {@code management.health.<name>.enabled} property is
|
||||
* {@code true}. Otherwise, matches if the value of the
|
||||
* {@code management.health.defaults.enabled} property is {@code true} or if it is not
|
||||
* configured.
|
||||
* Identifies a type as being an endpoint.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.0.0
|
||||
* @see EndpointDiscoverer
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@Documented
|
||||
@Conditional(OnEnabledHealthIndicatorCondition.class)
|
||||
public @interface ConditionalOnEnabledHealthIndicator {
|
||||
public @interface Endpoint {
|
||||
|
||||
/**
|
||||
* The name of the health indicator.
|
||||
* @return the name of the health indicator
|
||||
* The id of the endpoint.
|
||||
* @return the id
|
||||
*/
|
||||
String value();
|
||||
String id();
|
||||
|
||||
/**
|
||||
* Defines the {@link EndpointExposure technologies} over which the endpoint should be
|
||||
* exposed. By default, all technologies are supported.
|
||||
* @return the supported endpoint exposure technologies
|
||||
*/
|
||||
EndpointExposure[] exposure() default {};
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user