[bs-85] New name for production-ready features = "actuator"
[#49047535]
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.autoconfigure.service;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnClass;
|
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnMissingBean;
|
||||
import org.springframework.bootstrap.service.audit.AuditEventRepository;
|
||||
import org.springframework.bootstrap.service.audit.InMemoryAuditEventRepository;
|
||||
import org.springframework.bootstrap.service.audit.listener.AuditListener;
|
||||
import org.springframework.bootstrap.service.security.AuthenticationAuditListener;
|
||||
import org.springframework.bootstrap.service.security.AuthorizationAuditListener;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
@Configuration
|
||||
public class AuditConfiguration {
|
||||
|
||||
@Autowired(required = false)
|
||||
private AuditEventRepository auditEventRepository = new InMemoryAuditEventRepository();
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(AuditEventRepository.class)
|
||||
public AuditEventRepository auditEventRepository() throws Exception {
|
||||
return this.auditEventRepository;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AuditListener auditListener() throws Exception {
|
||||
return new AuditListener(this.auditEventRepository);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnClass(name = "org.springframework.security.authentication.event.AbstractAuthenticationEvent")
|
||||
public AuthenticationAuditListener authenticationAuditListener() throws Exception {
|
||||
return new AuthenticationAuditListener();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnClass(name = "org.springframework.security.access.event.AbstractAuthorizationEvent")
|
||||
public AuthorizationAuditListener authorizationAuditListener() throws Exception {
|
||||
return new AuthorizationAuditListener();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.autoconfigure.service;
|
||||
|
||||
import javax.servlet.Servlet;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnClass;
|
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnMissingBean;
|
||||
import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration;
|
||||
import org.springframework.bootstrap.service.health.HealthIndicator;
|
||||
import org.springframework.bootstrap.service.health.HealthzEndpoint;
|
||||
import org.springframework.bootstrap.service.health.VanillaHealthIndicator;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for /healthz endpoint.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class })
|
||||
@ConditionalOnMissingBean({ HealthzEndpoint.class })
|
||||
public class HealthzConfiguration {
|
||||
|
||||
@Autowired(required = false)
|
||||
private HealthIndicator<? extends Object> healthIndicator = new VanillaHealthIndicator();
|
||||
|
||||
@Bean
|
||||
public HealthzEndpoint<? extends Object> healthzEndpoint() {
|
||||
return new HealthzEndpoint<Object>(healthIndicator);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.autoconfigure.service;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.Servlet;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.bootstrap.bind.PropertiesConfigurationFactory;
|
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnClass;
|
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnMissingBean;
|
||||
import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration;
|
||||
import org.springframework.bootstrap.service.info.InfoEndpoint;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.StandardEnvironment;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.support.PropertiesLoaderUtils;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for /info endpoint.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class })
|
||||
@ConditionalOnMissingBean({ InfoEndpoint.class })
|
||||
public class InfoConfiguration {
|
||||
|
||||
@Resource(name = "infoMap")
|
||||
private Map<String, Object> infoMap;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("gitInfo")
|
||||
private GitInfo gitInfo;
|
||||
|
||||
@Bean
|
||||
public Map<String, Object> applicationInfo() {
|
||||
LinkedHashMap<String, Object> info = new LinkedHashMap<String, Object>();
|
||||
info.putAll(this.infoMap);
|
||||
if (this.gitInfo.getBranch() != null) {
|
||||
info.put("git", this.gitInfo);
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public InfoEndpoint infoEndpoint() {
|
||||
return new InfoEndpoint(applicationInfo());
|
||||
}
|
||||
|
||||
@Configuration
|
||||
public static class InfoPropertiesConfiguration {
|
||||
|
||||
@Autowired
|
||||
private ConfigurableEnvironment environment = new StandardEnvironment();
|
||||
|
||||
@Bean
|
||||
public PropertiesConfigurationFactory<GitInfo> gitInfo() throws IOException {
|
||||
PropertiesConfigurationFactory<GitInfo> factory = new PropertiesConfigurationFactory<GitInfo>(
|
||||
new GitInfo());
|
||||
factory.setTargetName("git");
|
||||
Properties properties = new Properties();
|
||||
if (new ClassPathResource("git.properties").exists()) {
|
||||
properties = PropertiesLoaderUtils.loadProperties(new ClassPathResource(
|
||||
"git.properties"));
|
||||
}
|
||||
factory.setProperties(properties);
|
||||
return factory;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PropertiesConfigurationFactory<Map<String, Object>> infoMap() {
|
||||
PropertiesConfigurationFactory<Map<String, Object>> factory = new PropertiesConfigurationFactory<Map<String, Object>>(
|
||||
new LinkedHashMap<String, Object>());
|
||||
factory.setTargetName("info");
|
||||
factory.setPropertySources(this.environment.getPropertySources());
|
||||
return factory;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class GitInfo {
|
||||
private String branch;
|
||||
private Commit commit = new Commit();
|
||||
|
||||
public String getBranch() {
|
||||
return this.branch;
|
||||
}
|
||||
|
||||
public void setBranch(String branch) {
|
||||
this.branch = branch;
|
||||
}
|
||||
|
||||
public Commit getCommit() {
|
||||
return this.commit;
|
||||
}
|
||||
|
||||
public static class Commit {
|
||||
private String id;
|
||||
private String time;
|
||||
|
||||
public String getId() {
|
||||
return this.id == null ? "" : (this.id.length() > 7 ? this.id.substring(
|
||||
0, 7) : this.id);
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getTime() {
|
||||
return this.time;
|
||||
}
|
||||
|
||||
public void setTime(String time) {
|
||||
this.time = time;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.autoconfigure.service;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnExpression;
|
||||
import org.springframework.bootstrap.context.embedded.AnnotationConfigEmbeddedWebApplicationContext;
|
||||
import org.springframework.bootstrap.service.properties.ManagementServerProperties;
|
||||
import org.springframework.bootstrap.service.properties.ServerProperties;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnExpression("${management.port:8080}>0")
|
||||
public class ManagementConfiguration implements ApplicationContextAware, DisposableBean,
|
||||
ApplicationListener<ContextRefreshedEvent> {
|
||||
|
||||
private ApplicationContext parent;
|
||||
private ConfigurableApplicationContext context;
|
||||
|
||||
@Autowired
|
||||
private ServerProperties configuration = new ServerProperties();
|
||||
|
||||
@Autowired
|
||||
private ManagementServerProperties management = new ManagementServerProperties();
|
||||
|
||||
@ConditionalOnExpression("${server.port:8080} == ${management.port:8080}")
|
||||
@Configuration
|
||||
@Import({ VarzConfiguration.class, HealthzConfiguration.class,
|
||||
ShutdownConfiguration.class, TraceConfiguration.class })
|
||||
public static class ManagementEndpointsConfiguration {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext)
|
||||
throws BeansException {
|
||||
this.parent = applicationContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
if (this.context != null) {
|
||||
this.context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ContextRefreshedEvent event) {
|
||||
if (event.getSource() != this.parent) {
|
||||
return;
|
||||
}
|
||||
if (this.configuration.getPort() != this.management.getPort()) {
|
||||
AnnotationConfigEmbeddedWebApplicationContext context = new AnnotationConfigEmbeddedWebApplicationContext();
|
||||
context.setParent(this.parent);
|
||||
context.register(ManagementServerConfiguration.class,
|
||||
VarzConfiguration.class, HealthzConfiguration.class,
|
||||
ShutdownConfiguration.class, TraceConfiguration.class);
|
||||
context.refresh();
|
||||
this.context = context;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.autoconfigure.service;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.HierarchicalBeanFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnBean;
|
||||
import org.springframework.bootstrap.context.embedded.AbstractEmbeddedServletContainerFactory;
|
||||
import org.springframework.bootstrap.context.embedded.EmbeddedServletContainerFactory;
|
||||
import org.springframework.bootstrap.context.embedded.ErrorPage;
|
||||
import org.springframework.bootstrap.context.embedded.jetty.JettyEmbeddedServletContainerFactory;
|
||||
import org.springframework.bootstrap.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
|
||||
import org.springframework.bootstrap.service.error.ErrorEndpoint;
|
||||
import org.springframework.bootstrap.service.properties.ManagementServerProperties;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
|
||||
/**
|
||||
* Configuration for creating a new container (e.g. tomcat) for the management endpoints.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
public class ManagementServerConfiguration implements BeanPostProcessor {
|
||||
|
||||
@Autowired
|
||||
private ManagementServerProperties configuration = new ManagementServerProperties();
|
||||
|
||||
private boolean initialized = false;
|
||||
|
||||
@Value("${endpoints.error.path:/error}")
|
||||
private String errorPath = "/error";
|
||||
|
||||
@Bean
|
||||
public DispatcherServlet dispatcherServlet() {
|
||||
return new DispatcherServlet();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer(
|
||||
ApplicationContext context) {
|
||||
return new PropertySourcesPlaceholderConfigurer();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ErrorEndpoint errorEndpoint() {
|
||||
return new ErrorEndpoint();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(TomcatEmbeddedServletContainerFactory.class)
|
||||
public EmbeddedServletContainerFactory tomcatContainer(
|
||||
HierarchicalBeanFactory beanFactory) {
|
||||
TomcatEmbeddedServletContainerFactory factory = beanFactory
|
||||
.getParentBeanFactory().getBean(
|
||||
TomcatEmbeddedServletContainerFactory.class);
|
||||
return factory.getChildContextFactory("Management");
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(JettyEmbeddedServletContainerFactory.class)
|
||||
public EmbeddedServletContainerFactory jettyContainer() {
|
||||
return new JettyEmbeddedServletContainerFactory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
|
||||
if (bean instanceof EmbeddedServletContainerFactory) {
|
||||
|
||||
if (bean instanceof AbstractEmbeddedServletContainerFactory
|
||||
&& !this.initialized) {
|
||||
|
||||
AbstractEmbeddedServletContainerFactory factory = (AbstractEmbeddedServletContainerFactory) bean;
|
||||
factory.setPort(this.configuration.getPort());
|
||||
factory.setContextPath(this.configuration.getContextPath());
|
||||
|
||||
factory.setErrorPages(Collections
|
||||
.singleton(new ErrorPage(this.errorPath)));
|
||||
this.initialized = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return bean;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.autoconfigure.service;
|
||||
|
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnMissingBean;
|
||||
import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration;
|
||||
import org.springframework.bootstrap.service.metrics.CounterService;
|
||||
import org.springframework.bootstrap.service.metrics.DefaultCounterService;
|
||||
import org.springframework.bootstrap.service.metrics.DefaultGaugeService;
|
||||
import org.springframework.bootstrap.service.metrics.GaugeService;
|
||||
import org.springframework.bootstrap.service.metrics.InMemoryMetricRepository;
|
||||
import org.springframework.bootstrap.service.metrics.MetricRepository;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for metrics services.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
@Configuration
|
||||
public class MetricConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean({ CounterService.class })
|
||||
public CounterService counterService() {
|
||||
return new DefaultCounterService(metricRepository());
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean({ GaugeService.class })
|
||||
public GaugeService gaugeService() {
|
||||
return new DefaultGaugeService(metricRepository());
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean({ MetricRepository.class })
|
||||
protected MetricRepository metricRepository() {
|
||||
return new InMemoryMetricRepository();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.autoconfigure.service;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.Servlet;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnBean;
|
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnClass;
|
||||
import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration;
|
||||
import org.springframework.bootstrap.service.metrics.CounterService;
|
||||
import org.springframework.bootstrap.service.metrics.GaugeService;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.web.filter.GenericFilterBean;
|
||||
import org.springframework.web.util.UrlPathHelper;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for service apps.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@Configuration
|
||||
// FIXME: make this conditional
|
||||
// @ConditionalOnBean({ CounterService.class, GaugeService.class })
|
||||
@ConditionalOnClass({ Servlet.class })
|
||||
public class MetricFilterConfiguration {
|
||||
|
||||
@Autowired(required = false)
|
||||
private CounterService counterService;
|
||||
|
||||
@Autowired(required = false)
|
||||
private GaugeService gaugeService;
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean({ CounterService.class, GaugeService.class })
|
||||
public Filter metricFilter() {
|
||||
return new CounterServiceFilter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter that counts requests and measures processing times.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
@Order(Integer.MIN_VALUE)
|
||||
// TODO: parameterize the order (ideally it runs before any other filter)
|
||||
private final class CounterServiceFilter extends GenericFilterBean {
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response,
|
||||
FilterChain chain) throws IOException, ServletException {
|
||||
HttpServletRequest servletRequest = (HttpServletRequest) request;
|
||||
HttpServletResponse servletResponse = (HttpServletResponse) response;
|
||||
UrlPathHelper helper = new UrlPathHelper();
|
||||
String suffix = helper.getPathWithinApplication(servletRequest);
|
||||
int status = 999;
|
||||
long t0 = System.currentTimeMillis();
|
||||
try {
|
||||
chain.doFilter(request, response);
|
||||
} finally {
|
||||
try {
|
||||
status = servletResponse.getStatus();
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
set("response", suffix, System.currentTimeMillis() - t0);
|
||||
increment("status." + status, suffix);
|
||||
}
|
||||
}
|
||||
|
||||
private void increment(String prefix, String suffix) {
|
||||
if (MetricFilterConfiguration.this.counterService != null) {
|
||||
String key = getKey(prefix + suffix);
|
||||
MetricFilterConfiguration.this.counterService.increment(key);
|
||||
}
|
||||
}
|
||||
|
||||
private void set(String prefix, String suffix, double value) {
|
||||
if (MetricFilterConfiguration.this.gaugeService != null) {
|
||||
String key = getKey(prefix + suffix);
|
||||
MetricFilterConfiguration.this.gaugeService.set(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
private String getKey(String string) {
|
||||
String value = string.replace("/", "."); // graphite compatible metric names
|
||||
value = value.replace("..", ".");
|
||||
if (value.endsWith(".")) {
|
||||
value = value + "root";
|
||||
}
|
||||
if (value.startsWith("_")) {
|
||||
value = value.substring(1);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.autoconfigure.service;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnClass;
|
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnMissingBean;
|
||||
import org.springframework.bootstrap.context.annotation.EnableConfigurationProperties;
|
||||
import org.springframework.bootstrap.service.properties.SecurityProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.authentication.AuthenticationEventPublisher;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
|
||||
import org.springframework.security.authentication.ProviderManager;
|
||||
import org.springframework.security.config.annotation.authentication.AuthenticationBuilder;
|
||||
import org.springframework.security.config.annotation.web.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.ExpressionUrlAuthorizations;
|
||||
import org.springframework.security.config.annotation.web.HttpConfigurator;
|
||||
import org.springframework.security.config.annotation.web.SpringSecurityFilterChainBuilder.IgnoredRequestRegistry;
|
||||
import org.springframework.security.config.annotation.web.WebSecurityConfigurerAdapter;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass({ EnableWebSecurity.class })
|
||||
@EnableWebSecurity
|
||||
@EnableConfigurationProperties(SecurityProperties.class)
|
||||
public class SecurityConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean({ AuthenticationEventPublisher.class })
|
||||
public AuthenticationEventPublisher authenticationEventPublisher() {
|
||||
return new DefaultAuthenticationEventPublisher();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public WebSecurityConfigurerAdapter webSecurityConfigurerAdapter() {
|
||||
return new BoostrapWebSecurityConfigurerAdapter();
|
||||
}
|
||||
|
||||
private static class BoostrapWebSecurityConfigurerAdapter extends
|
||||
WebSecurityConfigurerAdapter {
|
||||
|
||||
@Value("${endpoints.healthz.path:/healthz}")
|
||||
private String healthzPath = "/healthz";
|
||||
|
||||
@Value("${endpoints.info.path:/info}")
|
||||
private String infoPath = "/info";
|
||||
|
||||
@Autowired
|
||||
private SecurityProperties security;
|
||||
|
||||
@Autowired
|
||||
private AuthenticationEventPublisher authenticationEventPublisher;
|
||||
|
||||
@Override
|
||||
protected void ignoredRequests(IgnoredRequestRegistry ignoredRequests) {
|
||||
ignoredRequests.antMatchers(this.healthzPath);
|
||||
ignoredRequests.antMatchers(this.infoPath);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void authorizeUrls(ExpressionUrlAuthorizations interceptUrls) {
|
||||
interceptUrls.antMatchers("/**").hasRole("USER");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpConfigurator http) throws Exception {
|
||||
http.antMatcher("/**").httpBasic().and().anonymous().disable();
|
||||
if (this.security.isRequireSsl()) {
|
||||
http.requiresChannel().antMatchers("/**").requiresSecure();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthenticationManager authenticationManager() throws Exception {
|
||||
AuthenticationManager manager = super.authenticationManager();
|
||||
if (manager instanceof ProviderManager) {
|
||||
((ProviderManager) manager)
|
||||
.setAuthenticationEventPublisher(this.authenticationEventPublisher);
|
||||
}
|
||||
return manager;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnMissingBean(AuthenticationManager.class)
|
||||
@Configuration
|
||||
public static class AuthenticationManagerConfiguration {
|
||||
|
||||
@Bean
|
||||
public AuthenticationManager authenticationManager() throws Exception {
|
||||
return new AuthenticationBuilder().inMemoryAuthentication().withUser("user")
|
||||
.password("password").roles("USER").and().and().build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.autoconfigure.service;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import javax.servlet.Servlet;
|
||||
|
||||
import org.apache.catalina.valves.AccessLogValve;
|
||||
import org.apache.catalina.valves.RemoteIpValve;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnClass;
|
||||
import org.springframework.bootstrap.context.embedded.AbstractEmbeddedServletContainerFactory;
|
||||
import org.springframework.bootstrap.context.embedded.EmbeddedServletContainerFactory;
|
||||
import org.springframework.bootstrap.context.embedded.ErrorPage;
|
||||
import org.springframework.bootstrap.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
|
||||
import org.springframework.bootstrap.service.error.ErrorEndpoint;
|
||||
import org.springframework.bootstrap.service.properties.ServerProperties;
|
||||
import org.springframework.bootstrap.service.properties.ServerProperties.Tomcat;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Configuration for injecting externalized properties into the container (e.g. tomcat).
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
// Slight hack here (BeanPostProcessor), to force the server properties to be bound in
|
||||
// the right order
|
||||
@Configuration
|
||||
@ConditionalOnClass({ Servlet.class })
|
||||
@Order(Integer.MIN_VALUE)
|
||||
@Import(InfoConfiguration.class)
|
||||
public class ServerConfiguration implements BeanPostProcessor, BeanFactoryAware {
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
// Don't do this! We don't get a callback for our own dependencies (lifecycle).
|
||||
// @Autowired
|
||||
// private AbstractEmbeddedServletContainerFactory factory;
|
||||
|
||||
private boolean initialized = false;
|
||||
|
||||
@Value("${endpoints.error.path:/error}")
|
||||
private String errorPath = "/error";
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ErrorEndpoint errorEndpoint() {
|
||||
return new ErrorEndpoint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
|
||||
if (bean instanceof EmbeddedServletContainerFactory) {
|
||||
|
||||
if (bean instanceof AbstractEmbeddedServletContainerFactory
|
||||
&& !this.initialized) {
|
||||
|
||||
// Cannot use @Autowired because the injection happens too early
|
||||
ServerProperties server = this.beanFactory
|
||||
.getBean(ServerProperties.class);
|
||||
|
||||
AbstractEmbeddedServletContainerFactory factory = (AbstractEmbeddedServletContainerFactory) bean;
|
||||
factory.setPort(server.getPort());
|
||||
factory.setContextPath(server.getContextPath());
|
||||
|
||||
if (factory instanceof TomcatEmbeddedServletContainerFactory) {
|
||||
configureTomcat((TomcatEmbeddedServletContainerFactory) factory,
|
||||
server);
|
||||
}
|
||||
|
||||
factory.setErrorPages(Collections
|
||||
.singleton(new ErrorPage(this.errorPath)));
|
||||
this.initialized = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return bean;
|
||||
|
||||
}
|
||||
|
||||
private void configureTomcat(TomcatEmbeddedServletContainerFactory tomcatFactory,
|
||||
ServerProperties configuration) {
|
||||
|
||||
Tomcat tomcat = configuration.getTomcat();
|
||||
if (tomcat.getBasedir() != null) {
|
||||
tomcatFactory.setBaseDirectory(tomcat.getBasedir());
|
||||
}
|
||||
|
||||
String remoteIpHeader = tomcat.getRemoteIpHeader();
|
||||
String protocolHeader = tomcat.getProtocolHeader();
|
||||
|
||||
if (StringUtils.hasText(remoteIpHeader) || StringUtils.hasText(protocolHeader)) {
|
||||
RemoteIpValve valve = new RemoteIpValve();
|
||||
valve.setRemoteIpHeader(remoteIpHeader);
|
||||
valve.setProtocolHeader(protocolHeader);
|
||||
tomcatFactory.addContextValves(valve);
|
||||
}
|
||||
|
||||
String pattern = tomcat.getAccessLogPattern();
|
||||
if (pattern != null) {
|
||||
AccessLogValve valve = new AccessLogValve();
|
||||
valve.setPattern(pattern);
|
||||
valve.setSuffix(".log");
|
||||
tomcatFactory.addContextValves(valve);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.autoconfigure.service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnMissingBean;
|
||||
import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration;
|
||||
import org.springframework.bootstrap.context.annotation.EnableConfigurationProperties;
|
||||
import org.springframework.bootstrap.service.properties.EndpointsProperties;
|
||||
import org.springframework.bootstrap.service.properties.ManagementServerProperties;
|
||||
import org.springframework.bootstrap.service.properties.ServerProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
|
||||
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for service apps.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@Configuration
|
||||
@Import({ ManagementConfiguration.class, MetricConfiguration.class,
|
||||
ServerConfiguration.class, SecurityConfiguration.class,
|
||||
MetricFilterConfiguration.class, AuditConfiguration.class })
|
||||
public class ServiceAutoConfiguration extends WebMvcConfigurationSupport {
|
||||
|
||||
@Override
|
||||
protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
|
||||
addDefaultHttpMessageConverters(converters);
|
||||
for (HttpMessageConverter<?> converter : converters) {
|
||||
if (converter instanceof MappingJackson2HttpMessageConverter) {
|
||||
MappingJackson2HttpMessageConverter jacksonConverter = (MappingJackson2HttpMessageConverter) converter;
|
||||
jacksonConverter.getObjectMapper().disable(
|
||||
SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ServerProperties has to be declared in a non-conditional bean, so that it gets
|
||||
* added to the context early enough
|
||||
*/
|
||||
@EnableConfigurationProperties({ ServerProperties.class,
|
||||
ManagementServerProperties.class })
|
||||
public static class ServerPropertiesConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(EndpointsProperties.class)
|
||||
public EndpointsProperties endpointsProperties() {
|
||||
return new EndpointsProperties();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.autoconfigure.service;
|
||||
|
||||
import javax.servlet.Servlet;
|
||||
|
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnClass;
|
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnMissingBean;
|
||||
import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration;
|
||||
import org.springframework.bootstrap.service.shutdown.ShutdownEndpoint;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for /shutdown endpoint.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class })
|
||||
@ConditionalOnMissingBean({ ShutdownEndpoint.class })
|
||||
public class ShutdownConfiguration {
|
||||
|
||||
@Bean
|
||||
public ShutdownEndpoint shutdownEndpoint() {
|
||||
return new ShutdownEndpoint();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.autoconfigure.service;
|
||||
|
||||
import javax.servlet.Servlet;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnClass;
|
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnMissingBean;
|
||||
import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration;
|
||||
import org.springframework.bootstrap.service.security.SecurityFilterPostProcessor;
|
||||
import org.springframework.bootstrap.service.trace.InMemoryTraceRepository;
|
||||
import org.springframework.bootstrap.service.trace.TraceEndpoint;
|
||||
import org.springframework.bootstrap.service.trace.TraceRepository;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for /trace endpoint.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class })
|
||||
@ConditionalOnMissingBean({ TraceEndpoint.class })
|
||||
public class TraceConfiguration {
|
||||
|
||||
@Autowired
|
||||
private TraceRepository traceRepository;
|
||||
|
||||
@Configuration
|
||||
public static class SecurityFilterPostProcessorConfiguration {
|
||||
|
||||
@Autowired(required = false)
|
||||
private TraceRepository traceRepository = new InMemoryTraceRepository();
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(TraceRepository.class)
|
||||
protected TraceRepository traceRepository() {
|
||||
return this.traceRepository;
|
||||
}
|
||||
|
||||
@Value("${management.dump_requests:false}")
|
||||
private boolean dumpRequests;
|
||||
|
||||
@Bean
|
||||
@ConditionalOnClass(name = "org.springframework.security.web.SecurityFilterChain")
|
||||
public SecurityFilterPostProcessor securityFilterPostProcessor(
|
||||
BeanFactory beanFactory) {
|
||||
SecurityFilterPostProcessor processor = new SecurityFilterPostProcessor(
|
||||
this.traceRepository);
|
||||
processor.setDumpRequests(this.dumpRequests);
|
||||
return processor;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TraceEndpoint traceEndpoint() {
|
||||
return new TraceEndpoint(this.traceRepository);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.autoconfigure.service;
|
||||
|
||||
import javax.servlet.Servlet;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnClass;
|
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnMissingBean;
|
||||
import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration;
|
||||
import org.springframework.bootstrap.service.metrics.MetricRepository;
|
||||
import org.springframework.bootstrap.service.varz.PublicMetrics;
|
||||
import org.springframework.bootstrap.service.varz.VanillaPublicMetrics;
|
||||
import org.springframework.bootstrap.service.varz.VarzEndpoint;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for /varz endpoint.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class })
|
||||
@ConditionalOnMissingBean({ VarzEndpoint.class })
|
||||
public class VarzConfiguration {
|
||||
|
||||
@Autowired
|
||||
private MetricRepository repository;
|
||||
|
||||
@Autowired(required = false)
|
||||
private PublicMetrics metrics;
|
||||
|
||||
@Bean
|
||||
public VarzEndpoint varzEndpoint() {
|
||||
if (this.metrics == null) {
|
||||
this.metrics = new VanillaPublicMetrics(this.repository);
|
||||
}
|
||||
return new VarzEndpoint(this.metrics);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.service.audit;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A value object representing an audit event: at a particular time, a particular user or
|
||||
* agent carried out an action of a particular type. This object records the details of
|
||||
* such an event.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class AuditEvent {
|
||||
|
||||
final private Date timestamp;
|
||||
final private String principal;
|
||||
final private String type;
|
||||
final private Map<String, Object> data;
|
||||
|
||||
/**
|
||||
* Create a new audit event for the current time from data provided as name-value
|
||||
* pairs
|
||||
*/
|
||||
public AuditEvent(String principal, String type, String... data) {
|
||||
this(new Date(), principal, type, convert(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new audit event for the current time
|
||||
*/
|
||||
public AuditEvent(String principal, String type, Map<String, Object> data) {
|
||||
this(new Date(), principal, type, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new audit event.
|
||||
*/
|
||||
public AuditEvent(Date timestamp, String principal, String type,
|
||||
Map<String, Object> data) {
|
||||
this.timestamp = timestamp;
|
||||
this.principal = principal;
|
||||
this.type = type;
|
||||
this.data = Collections.unmodifiableMap(data);
|
||||
}
|
||||
|
||||
public Date getTimestamp() {
|
||||
return this.timestamp;
|
||||
}
|
||||
|
||||
public String getPrincipal() {
|
||||
return this.principal;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public Map<String, Object> getData() {
|
||||
return this.data;
|
||||
}
|
||||
|
||||
private static Map<String, Object> convert(String[] data) {
|
||||
Map<String, Object> result = new HashMap<String, Object>();
|
||||
for (String entry : data) {
|
||||
if (entry.contains("=")) {
|
||||
int index = entry.indexOf("=");
|
||||
result.put(entry.substring(0, index), entry.substring(index + 1));
|
||||
} else {
|
||||
result.put(entry, null);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AuditEvent [timestamp=" + this.timestamp + ", principal="
|
||||
+ this.principal + ", type=" + this.type + ", data=" + this.data + "]";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.service.audit;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public interface AuditEventRepository {
|
||||
|
||||
/**
|
||||
* Find audit events relating to the specified principal since the time provided.
|
||||
*
|
||||
* @param principal the principal name to search for
|
||||
* @param after timestamp of earliest result required
|
||||
* @return audit events relating to the principal
|
||||
*/
|
||||
List<AuditEvent> find(String principal, Date after);
|
||||
|
||||
/**
|
||||
* Log an event.
|
||||
*
|
||||
* @param event the audit event to log
|
||||
*/
|
||||
void add(AuditEvent event);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.service.audit;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class InMemoryAuditEventRepository implements AuditEventRepository {
|
||||
|
||||
private int capacity = 100;
|
||||
|
||||
private Map<String, List<AuditEvent>> events = new HashMap<String, List<AuditEvent>>();
|
||||
|
||||
/**
|
||||
* @param capacity the capacity to set
|
||||
*/
|
||||
public void setCapacity(int capacity) {
|
||||
this.capacity = capacity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AuditEvent> find(String principal, Date after) {
|
||||
synchronized (this.events) {
|
||||
return Collections.unmodifiableList(getEvents(principal));
|
||||
}
|
||||
}
|
||||
|
||||
private List<AuditEvent> getEvents(String principal) {
|
||||
if (!this.events.containsKey(principal)) {
|
||||
this.events.put(principal, new ArrayList<AuditEvent>());
|
||||
}
|
||||
return this.events.get(principal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(AuditEvent event) {
|
||||
synchronized (this.events) {
|
||||
List<AuditEvent> list = getEvents(event.getPrincipal());
|
||||
while (list.size() >= this.capacity) {
|
||||
list.remove(0);
|
||||
}
|
||||
list.add(event);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.service.audit.listener;
|
||||
|
||||
import org.springframework.bootstrap.service.audit.AuditEvent;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class AuditApplicationEvent extends ApplicationEvent {
|
||||
|
||||
private AuditEvent auditEvent;
|
||||
|
||||
/**
|
||||
* @param auditEvent the source of this event
|
||||
*/
|
||||
public AuditApplicationEvent(AuditEvent auditEvent) {
|
||||
super(auditEvent);
|
||||
this.auditEvent = auditEvent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the audit event
|
||||
*/
|
||||
public AuditEvent getAuditEvent() {
|
||||
return this.auditEvent;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.service.audit.listener;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.bootstrap.service.audit.AuditEventRepository;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class AuditListener implements ApplicationListener<AuditApplicationEvent> {
|
||||
|
||||
private static Log logger = LogFactory.getLog(AuditListener.class);
|
||||
|
||||
private final AuditEventRepository auditEventRepository;
|
||||
|
||||
public AuditListener(AuditEventRepository auditEventRepository) {
|
||||
this.auditEventRepository = auditEventRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(AuditApplicationEvent event) {
|
||||
logger.info(event.getAuditEvent());
|
||||
this.auditEventRepository.add(event.getAuditEvent());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.service.error;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.bootstrap.context.embedded.AbstractEmbeddedServletContainerFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
/**
|
||||
* Basic fallback global error endpoint, rendering servlet container error codes and
|
||||
* messages where available. More specific errors can be handled either using Spring MVC
|
||||
* abstractions (e.g. {@code @ExceptionHandler}) or by adding servlet
|
||||
* {@link AbstractEmbeddedServletContainerFactory#setErrorPages(java.util.Set) container
|
||||
* error pages}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@Controller
|
||||
public class ErrorEndpoint {
|
||||
|
||||
private Log logger = LogFactory.getLog(ErrorEndpoint.class);
|
||||
|
||||
@RequestMapping("${endpoints.error.path:/error}")
|
||||
@ResponseBody
|
||||
public Map<String, Object> error(HttpServletRequest request) {
|
||||
Map<String, Object> map = new LinkedHashMap<String, Object>();
|
||||
try {
|
||||
Throwable error = (Throwable) request
|
||||
.getAttribute("javax.servlet.error.exception");
|
||||
Object obj = request.getAttribute("javax.servlet.error.status_code");
|
||||
int status = 999;
|
||||
if (obj != null) {
|
||||
status = (Integer) obj;
|
||||
map.put("error", HttpStatus.valueOf(status).getReasonPhrase());
|
||||
} else {
|
||||
map.put("error", "None");
|
||||
}
|
||||
map.put("status", status);
|
||||
if (error != null) {
|
||||
while (error instanceof ServletException) {
|
||||
error = ((ServletException) error).getCause();
|
||||
}
|
||||
map.put("exception", error.getClass().getName());
|
||||
map.put("message", error.getMessage());
|
||||
String trace = request.getParameter("trace");
|
||||
if (trace != null && !"false".equals(trace.toLowerCase())) {
|
||||
StringWriter stackTrace = new StringWriter();
|
||||
error.printStackTrace(new PrintWriter(stackTrace));
|
||||
stackTrace.flush();
|
||||
map.put("trace", stackTrace.toString());
|
||||
}
|
||||
this.logger.error(error);
|
||||
} else {
|
||||
Object message = request.getAttribute("javax.servlet.error.message");
|
||||
map.put("message", message == null ? "No message available" : message);
|
||||
}
|
||||
return map;
|
||||
} catch (Exception e) {
|
||||
map.put("error", e.getClass().getName());
|
||||
map.put("message", e.getMessage());
|
||||
this.logger.error(e);
|
||||
return map;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.service.health;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public interface HealthIndicator<T> {
|
||||
|
||||
/**
|
||||
* @return an indication of health
|
||||
*/
|
||||
T health();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.service.health;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@Controller
|
||||
public class HealthzEndpoint<T> {
|
||||
|
||||
private HealthIndicator<? extends T> indicator;
|
||||
|
||||
/**
|
||||
* @param indicator
|
||||
*/
|
||||
public HealthzEndpoint(HealthIndicator<? extends T> indicator) {
|
||||
super();
|
||||
this.indicator = indicator;
|
||||
}
|
||||
|
||||
@RequestMapping("${endpoints.healthz.path:/healthz}")
|
||||
@ResponseBody
|
||||
public T healthz() {
|
||||
return this.indicator.health();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.service.health;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class VanillaHealthIndicator implements HealthIndicator<String> {
|
||||
|
||||
@Override
|
||||
public String health() {
|
||||
return "ok";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.service.info;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@Controller
|
||||
public class InfoEndpoint {
|
||||
|
||||
private Map<String, Object> info;
|
||||
|
||||
/**
|
||||
* @param info
|
||||
*/
|
||||
public InfoEndpoint(Map<String, Object> info) {
|
||||
this.info = new LinkedHashMap<String, Object>(info);
|
||||
this.info.putAll(getAdditionalInfo());
|
||||
}
|
||||
|
||||
@RequestMapping("${endpoints.info.path:/info}")
|
||||
@ResponseBody
|
||||
public Map<String, Object> info() {
|
||||
return this.info;
|
||||
}
|
||||
|
||||
protected Map<String, Object> getAdditionalInfo() {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.service.metrics;
|
||||
|
||||
public interface CounterService {
|
||||
|
||||
void increment(String metricName);
|
||||
|
||||
void decrement(String metricName);
|
||||
|
||||
void reset(String metricName);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.service.metrics;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class DefaultCounterService implements CounterService {
|
||||
|
||||
private MetricRepository counterRepository;
|
||||
|
||||
/**
|
||||
* @param counterRepository
|
||||
*/
|
||||
public DefaultCounterService(MetricRepository counterRepository) {
|
||||
super();
|
||||
this.counterRepository = counterRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void increment(String metricName) {
|
||||
this.counterRepository.increment(wrap(metricName), 1, new Date());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decrement(String metricName) {
|
||||
this.counterRepository.increment(wrap(metricName), -1, new Date());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset(String metricName) {
|
||||
this.counterRepository.set(wrap(metricName), 0, new Date());
|
||||
}
|
||||
|
||||
private String wrap(String metricName) {
|
||||
if (metricName.startsWith("counter")) {
|
||||
return metricName;
|
||||
} else {
|
||||
return "counter." + metricName;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.service.metrics;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class DefaultGaugeService implements GaugeService {
|
||||
|
||||
private MetricRepository metricRepository;
|
||||
|
||||
/**
|
||||
* @param counterRepository
|
||||
*/
|
||||
public DefaultGaugeService(MetricRepository counterRepository) {
|
||||
super();
|
||||
this.metricRepository = counterRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(String metricName, double value) {
|
||||
this.metricRepository.set(wrap(metricName), value, new Date());
|
||||
}
|
||||
|
||||
private String wrap(String metricName) {
|
||||
if (metricName.startsWith("gauge")) {
|
||||
return metricName;
|
||||
} else {
|
||||
return "gauge." + metricName;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.service.metrics;
|
||||
|
||||
public interface GaugeService {
|
||||
|
||||
void set(String metricName, double value);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.service.metrics;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class InMemoryMetricRepository implements MetricRepository {
|
||||
|
||||
private ConcurrentMap<String, Measurement> metrics = new ConcurrentHashMap<String, Measurement>();
|
||||
|
||||
@Override
|
||||
public void increment(String metricName, int amount, Date timestamp) {
|
||||
Measurement current = this.metrics.get(metricName);
|
||||
if (current != null) {
|
||||
Metric metric = current.getMetric();
|
||||
this.metrics.replace(metricName, current,
|
||||
new Measurement(timestamp, metric.increment(amount)));
|
||||
} else {
|
||||
this.metrics.putIfAbsent(metricName, new Measurement(timestamp, new Metric(
|
||||
metricName, amount)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(String metricName, double value, Date timestamp) {
|
||||
Measurement current = this.metrics.get(metricName);
|
||||
if (current != null) {
|
||||
Metric metric = current.getMetric();
|
||||
this.metrics.replace(metricName, current,
|
||||
new Measurement(timestamp, metric.set(value)));
|
||||
} else {
|
||||
this.metrics.putIfAbsent(metricName, new Measurement(timestamp, new Metric(
|
||||
metricName, value)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String metricName) {
|
||||
this.metrics.remove(metricName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Metric findOne(String metricName) {
|
||||
if (this.metrics.containsKey(metricName)) {
|
||||
return this.metrics.get(metricName).getMetric();
|
||||
}
|
||||
return new Metric(metricName, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Metric> findAll() {
|
||||
ArrayList<Metric> result = new ArrayList<Metric>();
|
||||
for (Measurement measurement : this.metrics.values()) {
|
||||
result.add(measurement.getMetric());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.service.metrics;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class Measurement {
|
||||
|
||||
private Date timestamp;
|
||||
|
||||
private Metric metric;
|
||||
|
||||
public Measurement(Date timestamp, Metric metric) {
|
||||
this.timestamp = timestamp;
|
||||
this.metric = metric;
|
||||
}
|
||||
|
||||
public Date getTimestamp() {
|
||||
return this.timestamp;
|
||||
}
|
||||
|
||||
public Metric getMetric() {
|
||||
return this.metric;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Measurement [dateTime=" + this.timestamp + ", metric=" + this.metric + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result
|
||||
+ ((this.timestamp == null) ? 0 : this.timestamp.hashCode());
|
||||
result = prime * result + ((this.metric == null) ? 0 : this.metric.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Measurement other = (Measurement) obj;
|
||||
if (this.timestamp == null) {
|
||||
if (other.timestamp != null)
|
||||
return false;
|
||||
} else if (!this.timestamp.equals(other.timestamp))
|
||||
return false;
|
||||
if (this.metric == null) {
|
||||
if (other.metric != null)
|
||||
return false;
|
||||
} else if (!this.metric.equals(other.metric))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.service.metrics;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class Metric {
|
||||
|
||||
private final String name;
|
||||
|
||||
private final double value;
|
||||
|
||||
public Metric(String name, double value) {
|
||||
super();
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public double getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public Metric increment(int amount) {
|
||||
return new Metric(this.name, new Double(((int) this.value) + amount));
|
||||
}
|
||||
|
||||
public Metric set(double value) {
|
||||
return new Metric(this.name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Metric [name=" + this.name + ", value=" + this.value + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((this.name == null) ? 0 : this.name.hashCode());
|
||||
long temp;
|
||||
temp = Double.doubleToLongBits(this.value);
|
||||
result = prime * result + (int) (temp ^ (temp >>> 32));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Metric other = (Metric) obj;
|
||||
if (this.name == null) {
|
||||
if (other.name != null)
|
||||
return false;
|
||||
} else if (!this.name.equals(other.name))
|
||||
return false;
|
||||
if (Double.doubleToLongBits(this.value) != Double.doubleToLongBits(other.value))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.service.metrics;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public interface MetricRepository {
|
||||
|
||||
void increment(String metricName, int amount, Date timestamp);
|
||||
|
||||
void set(String metricName, double value, Date timestamp);
|
||||
|
||||
void delete(String metricName);
|
||||
|
||||
Metric findOne(String metricName);
|
||||
|
||||
Collection<Metric> findAll();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.service.properties;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Pattern;
|
||||
|
||||
import org.springframework.bootstrap.context.annotation.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* Externalized configuration for endpoints (e.g. paths)
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
@ConfigurationProperties(name = "endpoints", ignoreUnknownFields = false)
|
||||
public class EndpointsProperties {
|
||||
|
||||
@Valid
|
||||
private Endpoint info = new Endpoint("/info");
|
||||
|
||||
@Valid
|
||||
private Endpoint varz = new Endpoint("/varz");
|
||||
|
||||
@Valid
|
||||
private Endpoint healthz = new Endpoint("/healthz");
|
||||
|
||||
@Valid
|
||||
private Endpoint error = new Endpoint("/error");
|
||||
|
||||
@Valid
|
||||
private Endpoint shutdown = new Endpoint("/shutdown");
|
||||
|
||||
@Valid
|
||||
private Endpoint trace = new Endpoint("/trace");
|
||||
|
||||
@Valid
|
||||
private Endpoint dump = new Endpoint("/dump");
|
||||
|
||||
public Endpoint getInfo() {
|
||||
return this.info;
|
||||
}
|
||||
|
||||
public Endpoint getVarz() {
|
||||
return this.varz;
|
||||
}
|
||||
|
||||
public Endpoint getHealthz() {
|
||||
return this.healthz;
|
||||
}
|
||||
|
||||
public Endpoint getError() {
|
||||
return this.error;
|
||||
}
|
||||
|
||||
public Endpoint getShutdown() {
|
||||
return this.shutdown;
|
||||
}
|
||||
|
||||
public Endpoint getTrace() {
|
||||
return this.trace;
|
||||
}
|
||||
|
||||
public Endpoint getDump() {
|
||||
return this.dump;
|
||||
}
|
||||
|
||||
public static class Endpoint {
|
||||
|
||||
@NotNull
|
||||
@Pattern(regexp = "/[^/]*", message = "Path must start with /")
|
||||
private String path;
|
||||
|
||||
public Endpoint() {
|
||||
}
|
||||
|
||||
public Endpoint(String path) {
|
||||
super();
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return this.path;
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.service.properties;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.springframework.bootstrap.context.annotation.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* Properties for the management server (e.g. port and path settings).
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@ConfigurationProperties(name = "management", ignoreUnknownFields = false)
|
||||
public class ManagementServerProperties {
|
||||
|
||||
private int port = 8080;
|
||||
|
||||
@NotNull
|
||||
private String contextPath = "";
|
||||
|
||||
private boolean allowShutdown = false;
|
||||
|
||||
public boolean isAllowShutdown() {
|
||||
return this.allowShutdown;
|
||||
}
|
||||
|
||||
public void setAllowShutdown(boolean allowShutdown) {
|
||||
this.allowShutdown = allowShutdown;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return this.port;
|
||||
}
|
||||
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public String getContextPath() {
|
||||
return this.contextPath;
|
||||
}
|
||||
|
||||
public void setContextPath(String contextPath) {
|
||||
this.contextPath = contextPath;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.service.properties;
|
||||
|
||||
import org.springframework.bootstrap.context.annotation.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* Properties for the security aspects of the service.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@ConfigurationProperties(name = "security", ignoreUnknownFields = false)
|
||||
public class SecurityProperties {
|
||||
|
||||
private boolean requireSsl;
|
||||
|
||||
public boolean isRequireSsl() {
|
||||
return requireSsl;
|
||||
}
|
||||
|
||||
public void setRequireSsl(boolean requireSsl) {
|
||||
this.requireSsl = requireSsl;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.service.properties;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.springframework.bootstrap.context.annotation.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* Properties for the web server (e.g. port and path settings).
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@ConfigurationProperties(name = "server", ignoreUnknownFields = false)
|
||||
public class ServerProperties {
|
||||
|
||||
private int port = 8080;
|
||||
|
||||
@NotNull
|
||||
private String contextPath = "";
|
||||
|
||||
private Tomcat tomcat = new Tomcat();
|
||||
|
||||
public Tomcat getTomcat() {
|
||||
return this.tomcat;
|
||||
}
|
||||
|
||||
public String getContextPath() {
|
||||
return this.contextPath;
|
||||
}
|
||||
|
||||
public void setContextPath(String contextPath) {
|
||||
this.contextPath = contextPath;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return this.port;
|
||||
}
|
||||
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public static class Tomcat {
|
||||
|
||||
private String accessLogPattern;
|
||||
|
||||
private String protocolHeader = "x-forwarded-proto";
|
||||
|
||||
private String remoteIpHeader = "x-forwarded-for";
|
||||
|
||||
private File basedir;
|
||||
|
||||
public File getBasedir() {
|
||||
return this.basedir;
|
||||
}
|
||||
|
||||
public void setBasedir(File basedir) {
|
||||
this.basedir = basedir;
|
||||
}
|
||||
|
||||
public String getAccessLogPattern() {
|
||||
return this.accessLogPattern;
|
||||
}
|
||||
|
||||
public void setAccessLogPattern(String accessLogPattern) {
|
||||
this.accessLogPattern = accessLogPattern;
|
||||
}
|
||||
|
||||
public String getProtocolHeader() {
|
||||
return this.protocolHeader;
|
||||
}
|
||||
|
||||
public void setProtocolHeader(String protocolHeader) {
|
||||
this.protocolHeader = protocolHeader;
|
||||
}
|
||||
|
||||
public String getRemoteIpHeader() {
|
||||
return this.remoteIpHeader;
|
||||
}
|
||||
|
||||
public void setRemoteIpHeader(String remoteIpHeader) {
|
||||
this.remoteIpHeader = remoteIpHeader;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.service.security;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.bootstrap.service.audit.AuditEvent;
|
||||
import org.springframework.bootstrap.service.audit.listener.AuditApplicationEvent;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.ApplicationEventPublisherAware;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.security.authentication.event.AbstractAuthenticationEvent;
|
||||
import org.springframework.security.authentication.event.AbstractAuthenticationFailureEvent;
|
||||
import org.springframework.security.web.authentication.switchuser.AuthenticationSwitchUserEvent;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class AuthenticationAuditListener implements
|
||||
ApplicationListener<AbstractAuthenticationEvent>, ApplicationEventPublisherAware {
|
||||
|
||||
private ApplicationEventPublisher publisher;
|
||||
|
||||
@Override
|
||||
public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
|
||||
this.publisher = publisher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(AbstractAuthenticationEvent event) {
|
||||
Map<String, Object> data = new HashMap<String, Object>();
|
||||
if (event instanceof AbstractAuthenticationFailureEvent) {
|
||||
data.put("type", ((AbstractAuthenticationFailureEvent) event).getException()
|
||||
.getClass().getName());
|
||||
data.put("message", ((AbstractAuthenticationFailureEvent) event)
|
||||
.getException().getMessage());
|
||||
publish(new AuditEvent(event.getAuthentication().getName(),
|
||||
"AUTHENTICATION_FAILURE", data));
|
||||
} else if (event instanceof AuthenticationSwitchUserEvent) {
|
||||
if (event.getAuthentication().getDetails() != null) {
|
||||
data.put("details", event.getAuthentication().getDetails());
|
||||
}
|
||||
data.put("target", ((AuthenticationSwitchUserEvent) event).getTargetUser()
|
||||
.getUsername());
|
||||
publish(new AuditEvent(event.getAuthentication().getName(),
|
||||
"AUTHENTICATION_SWITCH", data));
|
||||
|
||||
} else {
|
||||
if (event.getAuthentication().getDetails() != null) {
|
||||
data.put("details", event.getAuthentication().getDetails());
|
||||
}
|
||||
publish(new AuditEvent(event.getAuthentication().getName(),
|
||||
"AUTHENTICATION_SUCCESS", data));
|
||||
}
|
||||
}
|
||||
|
||||
private void publish(AuditEvent event) {
|
||||
if (this.publisher != null) {
|
||||
this.publisher.publishEvent(new AuditApplicationEvent(event));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.service.security;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.bootstrap.service.audit.AuditEvent;
|
||||
import org.springframework.bootstrap.service.audit.listener.AuditApplicationEvent;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.ApplicationEventPublisherAware;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.security.access.event.AbstractAuthorizationEvent;
|
||||
import org.springframework.security.access.event.AuthenticationCredentialsNotFoundEvent;
|
||||
import org.springframework.security.access.event.AuthorizationFailureEvent;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class AuthorizationAuditListener implements
|
||||
ApplicationListener<AbstractAuthorizationEvent>, ApplicationEventPublisherAware {
|
||||
|
||||
private ApplicationEventPublisher publisher;
|
||||
|
||||
@Override
|
||||
public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
|
||||
this.publisher = publisher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(AbstractAuthorizationEvent event) {
|
||||
Map<String, Object> data = new HashMap<String, Object>();
|
||||
if (event instanceof AuthenticationCredentialsNotFoundEvent) {
|
||||
data.put("type", ((AuthenticationCredentialsNotFoundEvent) event)
|
||||
.getCredentialsNotFoundException().getClass().getName());
|
||||
data.put("message", ((AuthenticationCredentialsNotFoundEvent) event)
|
||||
.getCredentialsNotFoundException().getMessage());
|
||||
publish(new AuditEvent("<unknown>", "AUTHENTICATION_FAILURE", data));
|
||||
} else if (event instanceof AuthorizationFailureEvent) {
|
||||
data.put("type", ((AuthorizationFailureEvent) event)
|
||||
.getAccessDeniedException().getClass().getName());
|
||||
data.put("message", ((AuthorizationFailureEvent) event)
|
||||
.getAccessDeniedException().getMessage());
|
||||
publish(new AuditEvent(((AuthorizationFailureEvent) event)
|
||||
.getAuthentication().getName(), "AUTHORIZATION_FAILURE", data));
|
||||
}
|
||||
}
|
||||
|
||||
private void publish(AuditEvent event) {
|
||||
if (this.publisher != null) {
|
||||
this.publisher.publishEvent(new AuditApplicationEvent(event));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.service.security;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
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.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.bootstrap.service.trace.InMemoryTraceRepository;
|
||||
import org.springframework.bootstrap.service.trace.TraceRepository;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
/**
|
||||
* Bean post processor that adds a filter to Spring Security. The filter (optionally) logs
|
||||
* request headers at trace level and also sends the headers to a {@link TraceRepository}
|
||||
* for later analysis.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class SecurityFilterPostProcessor implements BeanPostProcessor, Ordered {
|
||||
|
||||
private final static Log logger = LogFactory
|
||||
.getLog(SecurityFilterPostProcessor.class);
|
||||
private boolean dumpRequests = false;
|
||||
private List<String> ignore = Collections.emptyList();
|
||||
|
||||
private TraceRepository traceRepository = new InMemoryTraceRepository();
|
||||
|
||||
private int order = Integer.MAX_VALUE;
|
||||
|
||||
/**
|
||||
* @param order the order to set
|
||||
*/
|
||||
public void setOrder(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return this.order;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param traceRepository
|
||||
*/
|
||||
public SecurityFilterPostProcessor(TraceRepository traceRepository) {
|
||||
super();
|
||||
this.traceRepository = traceRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* List of filter chains which should be ignored completely.
|
||||
*/
|
||||
public void setIgnore(List<String> ignore) {
|
||||
Assert.notNull(ignore);
|
||||
this.ignore = ignore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Debugging feature. If enabled, and trace logging is enabled
|
||||
*/
|
||||
public void setDumpRequests(boolean dumpRequests) {
|
||||
this.dumpRequests = dumpRequests;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
|
||||
if (!this.ignore.contains(beanName)) {
|
||||
if (bean instanceof FilterChainProxy) {
|
||||
FilterChainProxy proxy = (FilterChainProxy) bean;
|
||||
for (SecurityFilterChain filterChain : proxy.getFilterChains()) {
|
||||
processFilterChain(filterChain, beanName);
|
||||
}
|
||||
}
|
||||
if (bean instanceof SecurityFilterChain) {
|
||||
processFilterChain((SecurityFilterChain) bean, beanName);
|
||||
}
|
||||
}
|
||||
|
||||
return bean;
|
||||
|
||||
}
|
||||
|
||||
private void processFilterChain(SecurityFilterChain filterChain, String beanName) {
|
||||
logger.info("Processing security filter chain " + beanName);
|
||||
Filter loggingFilter = new WebRequestLoggingFilter(beanName);
|
||||
filterChain.getFilters().add(0, loggingFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
class WebRequestLoggingFilter implements Filter {
|
||||
|
||||
final Log logger = LogFactory.getLog(WebRequestLoggingFilter.class);
|
||||
private final String name;
|
||||
private ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
WebRequestLoggingFilter(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
HttpServletRequest request = (HttpServletRequest) req;
|
||||
HttpServletResponse response = (HttpServletResponse) res;
|
||||
|
||||
Map<String, Object> trace = getTrace(request);
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> headers = (Map<String, Object>) trace.get("headers");
|
||||
SecurityFilterPostProcessor.this.traceRepository.add(trace);
|
||||
if (this.logger.isTraceEnabled()) {
|
||||
this.logger.trace("Filter chain '" + this.name + "' processing request "
|
||||
+ request.getMethod() + " " + request.getRequestURI());
|
||||
if (SecurityFilterPostProcessor.this.dumpRequests) {
|
||||
try {
|
||||
this.logger.trace("Headers: "
|
||||
+ this.objectMapper.writeValueAsString(headers));
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new IllegalStateException("Cannot create JSON", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
protected Map<String, Object> getTrace(HttpServletRequest request) {
|
||||
|
||||
Map<String, Object> map = new LinkedHashMap<String, Object>();
|
||||
Enumeration<String> names = request.getHeaderNames();
|
||||
|
||||
while (names.hasMoreElements()) {
|
||||
String name = names.nextElement();
|
||||
List<String> values = Collections.list(request.getHeaders(name));
|
||||
Object value = values;
|
||||
if (values.size() == 1) {
|
||||
value = values.get(0);
|
||||
} else if (values.isEmpty()) {
|
||||
value = "";
|
||||
}
|
||||
map.put(name, value);
|
||||
|
||||
}
|
||||
Map<String, Object> trace = new LinkedHashMap<String, Object>();
|
||||
trace.put("chain", this.name);
|
||||
trace.put("method", request.getMethod());
|
||||
trace.put("path", request.getRequestURI());
|
||||
trace.put("headers", map);
|
||||
return trace;
|
||||
}
|
||||
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.service.shutdown;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.bootstrap.service.properties.ManagementServerProperties;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.context.support.ServletRequestHandledEvent;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
@Controller
|
||||
public class ShutdownEndpoint implements ApplicationContextAware,
|
||||
ApplicationListener<ServletRequestHandledEvent> {
|
||||
|
||||
private static Log logger = LogFactory.getLog(ShutdownEndpoint.class);
|
||||
|
||||
private ConfigurableApplicationContext context;
|
||||
|
||||
@Autowired
|
||||
private ManagementServerProperties configuration = new ManagementServerProperties();
|
||||
|
||||
private boolean shuttingDown = false;
|
||||
|
||||
@RequestMapping(value = "${endpoints.shutdown.path:/shutdown}", method = RequestMethod.POST)
|
||||
@ResponseBody
|
||||
public Map<String, Object> shutdown() {
|
||||
if (this.configuration.isAllowShutdown()) {
|
||||
this.shuttingDown = true;
|
||||
return Collections.<String, Object> singletonMap("message",
|
||||
"Shutting down, bye...");
|
||||
} else {
|
||||
return Collections.<String, Object> singletonMap("message",
|
||||
"Shutdown not enabled, sorry.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext context) throws BeansException {
|
||||
if (context instanceof ConfigurableApplicationContext) {
|
||||
this.context = (ConfigurableApplicationContext) context;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ServletRequestHandledEvent event) {
|
||||
|
||||
if (this.context != null && this.configuration.isAllowShutdown()
|
||||
&& this.shuttingDown) {
|
||||
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
logger.info("Shutting down Spring in response to admin request");
|
||||
ConfigurableApplicationContext context = ShutdownEndpoint.this.context;
|
||||
ApplicationContext parent = context.getParent();
|
||||
context.close();
|
||||
if (parent != null
|
||||
&& parent instanceof ConfigurableApplicationContext) {
|
||||
context = (ConfigurableApplicationContext) parent;
|
||||
context.close();
|
||||
parent = context.getParent();
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.service.trace;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class InMemoryTraceRepository implements TraceRepository {
|
||||
|
||||
private int capacity = 100;
|
||||
|
||||
private List<Trace> traces = new ArrayList<Trace>();
|
||||
|
||||
/**
|
||||
* @param capacity the capacity to set
|
||||
*/
|
||||
public void setCapacity(int capacity) {
|
||||
this.capacity = capacity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Trace> traces() {
|
||||
synchronized (this.traces) {
|
||||
return Collections.unmodifiableList(this.traces);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(Map<String, Object> map) {
|
||||
Trace trace = new Trace(new Date(), map);
|
||||
synchronized (this.traces) {
|
||||
while (this.traces.size() >= this.capacity) {
|
||||
this.traces.remove(0);
|
||||
}
|
||||
this.traces.add(trace);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.service.trace;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class Trace {
|
||||
|
||||
private Date timestamp;
|
||||
|
||||
private Map<String, Object> info;
|
||||
|
||||
public Trace(Date timestamp, Map<String, Object> info) {
|
||||
super();
|
||||
this.timestamp = timestamp;
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
public Date getTimestamp() {
|
||||
return this.timestamp;
|
||||
}
|
||||
|
||||
public Map<String, Object> getInfo() {
|
||||
return this.info;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.service.trace;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.ThreadInfo;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@Controller
|
||||
public class TraceEndpoint {
|
||||
|
||||
private TraceRepository tracer;
|
||||
|
||||
/**
|
||||
* @param tracer
|
||||
*/
|
||||
public TraceEndpoint(TraceRepository tracer) {
|
||||
super();
|
||||
this.tracer = tracer;
|
||||
}
|
||||
|
||||
@RequestMapping("${endpoints.trace.path:/trace}")
|
||||
@ResponseBody
|
||||
public List<Trace> trace() {
|
||||
return this.tracer.traces();
|
||||
}
|
||||
|
||||
@RequestMapping("${endpoints.dump.path:/dump}")
|
||||
@ResponseBody
|
||||
public List<ThreadInfo> dump() {
|
||||
return Arrays.asList(ManagementFactory.getThreadMXBean().dumpAllThreads(true,
|
||||
true));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.service.trace;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A repository for traces. Traces are simple documents (maps) with a timestamp, and can
|
||||
* be used for analysing contextual information like HTTP headers.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public interface TraceRepository {
|
||||
|
||||
List<Trace> traces();
|
||||
|
||||
void add(Map<String, Object> trace);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.service.varz;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.bootstrap.service.metrics.Metric;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public interface PublicMetrics {
|
||||
|
||||
/**
|
||||
* @return an indication of current state through metrics
|
||||
*/
|
||||
Collection<Metric> metrics();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.service.varz;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
|
||||
import org.springframework.bootstrap.service.metrics.Metric;
|
||||
import org.springframework.bootstrap.service.metrics.MetricRepository;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class VanillaPublicMetrics implements PublicMetrics {
|
||||
|
||||
private MetricRepository metricRepository;
|
||||
|
||||
public VanillaPublicMetrics(MetricRepository metricRepository) {
|
||||
Assert.notNull(metricRepository, "A MetricRepository must be provided");
|
||||
this.metricRepository = metricRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Metric> metrics() {
|
||||
Collection<Metric> result = new LinkedHashSet<Metric>(
|
||||
this.metricRepository.findAll());
|
||||
result.add(new Metric("mem", new Long(Runtime.getRuntime().totalMemory()) / 1024));
|
||||
result.add(new Metric("mem.free",
|
||||
new Long(Runtime.getRuntime().freeMemory()) / 1024));
|
||||
result.add(new Metric("processors", Runtime.getRuntime().availableProcessors()));
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.service.varz;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.bootstrap.service.metrics.Metric;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@Controller
|
||||
public class VarzEndpoint {
|
||||
|
||||
private PublicMetrics metrics;
|
||||
|
||||
/**
|
||||
* @param metrics
|
||||
*/
|
||||
public VarzEndpoint(PublicMetrics metrics) {
|
||||
this.metrics = metrics;
|
||||
}
|
||||
|
||||
@RequestMapping("${endpoints.varz.path:/varz}")
|
||||
@ResponseBody
|
||||
public Map<String, Object> varz() {
|
||||
Map<String, Object> result = new LinkedHashMap<String, Object>();
|
||||
for (Metric metric : this.metrics.metrics()) {
|
||||
result.put(metric.getName(), metric.getValue());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
org.springframework.bootstrap.context.annotation.EnableAutoConfiguration=\
|
||||
org.springframework.bootstrap.autoconfigure.service.ServiceAutoConfiguration
|
||||
org.springframework.context.ApplicationContextInitializer=\
|
||||
org.springframework.bootstrap.logging.LoggingInitializer
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.service.audit;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class AuditEventTests {
|
||||
|
||||
@Test
|
||||
public void testNowEvent() throws Exception {
|
||||
AuditEvent event = new AuditEvent("phil", "UNKNOWN", Collections.singletonMap(
|
||||
"a", (Object) "b"));
|
||||
assertEquals("b", event.getData().get("a"));
|
||||
assertEquals("UNKNOWN", event.getType());
|
||||
assertEquals("phil", event.getPrincipal());
|
||||
assertNotNull(event.getTimestamp());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConvertStringsToData() throws Exception {
|
||||
AuditEvent event = new AuditEvent("phil", "UNKNOWN", "a=b", "c=d");
|
||||
assertEquals("b", event.getData().get("a"));
|
||||
assertEquals("d", event.getData().get("c"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.service.audit;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class InMemoryAuditEventRepositoryTests {
|
||||
|
||||
private InMemoryAuditEventRepository repository = new InMemoryAuditEventRepository();
|
||||
|
||||
@Test
|
||||
public void testAddToCapacity() throws Exception {
|
||||
this.repository.setCapacity(2);
|
||||
this.repository.add(new AuditEvent("phil", "UNKNOWN"));
|
||||
this.repository.add(new AuditEvent("phil", "UNKNOWN"));
|
||||
this.repository.add(new AuditEvent("dave", "UNKNOWN"));
|
||||
this.repository.add(new AuditEvent("dave", "UNKNOWN"));
|
||||
this.repository.add(new AuditEvent("phil", "UNKNOWN"));
|
||||
assertEquals(2, this.repository.find("phil", new Date(0L)).size());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.service.properties;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Externalized configuration for endpoints (e.g. paths)
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class EndpointsPropertiesTests {
|
||||
|
||||
private EndpointsProperties properties = new EndpointsProperties();
|
||||
|
||||
@Test
|
||||
public void testDefaultPathValid() throws Exception {
|
||||
assertEquals("/error", this.properties.getError().getPath());
|
||||
Errors errors = validate(this.properties);
|
||||
assertFalse(errors.hasErrors());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryPathValid() throws Exception {
|
||||
Errors errors = validate(new EndpointsProperties.Endpoint("/foo?bar"));
|
||||
assertFalse(errors.hasErrors());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyPathInvalid() throws Exception {
|
||||
Errors errors = validate(new EndpointsProperties.Endpoint(""));
|
||||
assertTrue(errors.hasErrors());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoubleSlashInvalid() throws Exception {
|
||||
Errors errors = validate(new EndpointsProperties.Endpoint("//foo"));
|
||||
assertTrue(errors.hasErrors());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyPathInProperties() throws Exception {
|
||||
this.properties.getError().setPath("");
|
||||
Errors errors = validate(this.properties);
|
||||
assertTrue(errors.hasErrors());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
private Errors validate(Object target) {
|
||||
BindException errors = new BindException(target, "properties");
|
||||
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||
validator.afterPropertiesSet();
|
||||
validator.validate(target, errors);
|
||||
return errors;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.service.security;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.bootstrap.service.security.SecurityFilterPostProcessor;
|
||||
import org.springframework.bootstrap.service.security.SecurityFilterPostProcessor.WebRequestLoggingFilter;
|
||||
import org.springframework.bootstrap.service.trace.InMemoryTraceRepository;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class SecurityFilterPostProcessorTests {
|
||||
|
||||
private SecurityFilterPostProcessor processor = new SecurityFilterPostProcessor(
|
||||
new InMemoryTraceRepository());
|
||||
|
||||
@Test
|
||||
public void filterDumpsRequest() {
|
||||
WebRequestLoggingFilter filter = this.processor.new WebRequestLoggingFilter("foo");
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
||||
request.addHeader("Accept", "application/json");
|
||||
Map<String, Object> trace = filter.getTrace(request);
|
||||
assertEquals("GET", trace.get("method"));
|
||||
assertEquals("/foo", trace.get("path"));
|
||||
assertEquals("{Accept=application/json}", trace.get("headers").toString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.service.trace;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class InMemoryTraceRepositoryTests {
|
||||
|
||||
private InMemoryTraceRepository repository = new InMemoryTraceRepository();
|
||||
|
||||
@Test
|
||||
public void capacityLimited() {
|
||||
this.repository.setCapacity(2);
|
||||
this.repository.add(Collections.<String, Object> singletonMap("foo", "bar"));
|
||||
this.repository.add(Collections.<String, Object> singletonMap("bar", "foo"));
|
||||
this.repository.add(Collections.<String, Object> singletonMap("bar", "bar"));
|
||||
List<Trace> traces = this.repository.traces();
|
||||
assertEquals(2, traces.size());
|
||||
assertEquals("bar", traces.get(1).getInfo().get("bar"));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user