Commit 7f1264bb authored by Dave Syer's avatar Dave Syer Committed by Phillip Webb

Replace @FrameworkEndpoint with MvcEndpoint interface

parent 87e00cfa
......@@ -17,8 +17,6 @@
package org.springframework.boot.actuate.autoconfigure;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
......@@ -30,23 +28,20 @@ import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.boot.actuate.endpoint.Endpoint;
import org.springframework.boot.actuate.endpoint.EnvironmentEndpoint;
import org.springframework.boot.actuate.endpoint.MetricsEndpoint;
import org.springframework.boot.actuate.endpoint.ShutdownEndpoint;
import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping;
import org.springframework.boot.actuate.endpoint.mvc.EnvironmentMvcEndpoint;
import org.springframework.boot.actuate.endpoint.mvc.GenericMvcEndpoint;
import org.springframework.boot.actuate.endpoint.mvc.MetricsMvcEndpoint;
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoints;
import org.springframework.boot.actuate.endpoint.mvc.ShutdownMvcEndpoint;
import org.springframework.boot.actuate.properties.ManagementServerProperties;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
......@@ -63,7 +58,6 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.servlet.DispatcherServlet;
......@@ -97,7 +91,8 @@ public class EndpointWebMvcAutoConfiguration implements ApplicationContextAware,
@Bean
@ConditionalOnMissingBean
public EndpointHandlerMapping endpointHandlerMapping() {
EndpointHandlerMapping mapping = new EndpointHandlerMapping();
EndpointHandlerMapping mapping = new EndpointHandlerMapping(mvcEndpoints()
.getEndpoints());
mapping.setDisabled(ManagementServerPort.get(this.applicationContext) != ManagementServerPort.SAME);
mapping.setPrefix(this.managementServerProperties.getContextPath());
return mapping;
......@@ -133,48 +128,28 @@ public class EndpointWebMvcAutoConfiguration implements ApplicationContextAware,
};
}
@Component
protected static class GenericEndpointPostProcessor implements
BeanDefinitionRegistryPostProcessor {
private BeanDefinitionRegistry registry;
private Map<Class<? extends Endpoint<?>>, Class<?>> endpointTypes = new HashMap<Class<? extends Endpoint<?>>, Class<?>>();
public GenericEndpointPostProcessor() {
this.endpointTypes.put(EnvironmentEndpoint.class,
EnvironmentMvcEndpoint.class);
this.endpointTypes.put(MetricsEndpoint.class, MetricsMvcEndpoint.class);
this.endpointTypes.put(ShutdownEndpoint.class, ShutdownMvcEndpoint.class);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException {
for (String name : beanFactory.getBeanNamesForType(Endpoint.class)) {
Class<?> type = getTypeForEndpoint(beanFactory.getType(name));
BeanDefinitionBuilder bean = BeanDefinitionBuilder
.genericBeanDefinition(type);
bean.addConstructorArgReference(name);
this.registry.registerBeanDefinition("mvc." + name,
bean.getBeanDefinition());
}
}
@Bean
@ConditionalOnMissingBean
public MvcEndpoints mvcEndpoints() {
return new MvcEndpoints();
}
protected Class<?> getTypeForEndpoint(Class<?> endpoint) {
Class<?> type = GenericMvcEndpoint.class;
if (this.endpointTypes.containsKey(endpoint)) {
type = this.endpointTypes.get(endpoint);
}
return type;
}
@Bean
@ConditionalOnBean(EnvironmentEndpoint.class)
public EnvironmentMvcEndpoint environmentMvcEndpoint(EnvironmentEndpoint delegate) {
return new EnvironmentMvcEndpoint(delegate);
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
throws BeansException {
this.registry = registry;
}
@Bean
@ConditionalOnBean(MetricsEndpoint.class)
public MetricsMvcEndpoint metricsMvcEndpoint(MetricsEndpoint delegate) {
return new MetricsMvcEndpoint(delegate);
}
@Bean
@ConditionalOnBean(ShutdownEndpoint.class)
public ShutdownMvcEndpoint shutdownMvcEndpoint(ShutdownEndpoint delegate) {
return new ShutdownMvcEndpoint(delegate);
}
private void createChildManagementContext() {
......
......@@ -16,6 +16,9 @@
package org.springframework.boot.actuate.autoconfigure;
import java.util.HashSet;
import java.util.Set;
import javax.servlet.Filter;
import org.springframework.beans.factory.BeanFactory;
......@@ -24,13 +27,16 @@ import org.springframework.beans.factory.HierarchicalBeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.actuate.endpoint.ManagementErrorEndpoint;
import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping;
import org.springframework.boot.actuate.endpoint.mvc.ManagementErrorEndpoint;
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoints;
import org.springframework.boot.actuate.properties.ManagementServerProperties;
import org.springframework.boot.actuate.web.ErrorController;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.EmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
......@@ -38,7 +44,6 @@ import org.springframework.boot.context.embedded.ErrorPage;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.HandlerAdapter;
import org.springframework.web.servlet.HandlerMapping;
......@@ -99,16 +104,19 @@ public class EndpointWebMvcChildContextConfiguration {
}
@Bean
public HandlerAdapter handlerAdapter() {
public HandlerAdapter handlerAdapter(HttpMessageConverters converters) {
// TODO: maybe this needs more configuration for non-basic response use cases
RequestMappingHandlerAdapter adapter = new RequestMappingHandlerAdapter();
adapter.setMessageConverters(new RestTemplate().getMessageConverters());
adapter.setMessageConverters(converters.getConverters());
return adapter;
}
@Bean
public HandlerMapping handlerMapping() {
EndpointHandlerMapping mapping = new EndpointHandlerMapping();
public HandlerMapping handlerMapping(MvcEndpoints endpoints,
ListableBeanFactory beanFactory) {
Set<MvcEndpoint> set = new HashSet<MvcEndpoint>(endpoints.getEndpoints());
set.addAll(beanFactory.getBeansOfType(MvcEndpoint.class).values());
EndpointHandlerMapping mapping = new EndpointHandlerMapping(set);
// In a child context we definitely want to see the parent endpoints
mapping.setDetectHandlerMethodsInAncestorContexts(true);
return mapping;
......
......@@ -19,6 +19,7 @@ package org.springframework.boot.actuate.autoconfigure;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import javax.annotation.PostConstruct;
import javax.servlet.Filter;
......@@ -210,7 +211,7 @@ public class ManagementSecurityAutoConfiguration {
return NO_PATHS;
}
List<Endpoint<?>> endpoints = endpointHandlerMapping.getEndpoints();
Set<? extends Endpoint<?>> endpoints = endpointHandlerMapping.getEndpoints();
List<String> paths = new ArrayList<String>(endpoints.size());
for (Endpoint<?> endpoint : endpoints) {
if (endpoint.isSensitive() == secure) {
......
......@@ -21,7 +21,6 @@ import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.endpoint.AutoConfigurationReportEndpoint.Report;
import org.springframework.boot.actuate.endpoint.mvc.FrameworkEndpoint;
import org.springframework.boot.autoconfigure.AutoConfigurationReport;
import org.springframework.boot.autoconfigure.AutoConfigurationReport.ConditionAndOutcome;
import org.springframework.boot.autoconfigure.AutoConfigurationReport.ConditionAndOutcomes;
......@@ -32,8 +31,6 @@ import org.springframework.util.ClassUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
......@@ -45,7 +42,6 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder;
* @author Dave Syer
*/
@ConfigurationProperties(name = "endpoints.autoconfig", ignoreUnknownFields = false)
@FrameworkEndpoint
public class AutoConfigurationReportEndpoint extends AbstractEndpoint<Report> {
@Autowired
......@@ -56,8 +52,6 @@ public class AutoConfigurationReportEndpoint extends AbstractEndpoint<Report> {
}
@Override
@RequestMapping
@ResponseBody
public Report invoke() {
return new Report(this.autoConfigurationReport);
}
......
......@@ -17,17 +17,13 @@
package org.springframework.boot.actuate.endpoint.mvc;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.actuate.endpoint.Endpoint;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerMapping;
......@@ -56,9 +52,9 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandl
*
*/
public class EndpointHandlerMapping extends RequestMappingHandlerMapping implements
InitializingBean, ApplicationContextAware {
ApplicationContextAware {
private List<Endpoint<?>> endpoints;
private Set<? extends MvcEndpoint> endpoints;
private String prefix = "";
......@@ -67,8 +63,10 @@ public class EndpointHandlerMapping extends RequestMappingHandlerMapping impleme
/**
* Create a new {@link EndpointHandlerMapping} instance. All {@link Endpoint}s will be
* detected from the {@link ApplicationContext}.
* @param endpoints
*/
public EndpointHandlerMapping() {
public EndpointHandlerMapping(Collection<? extends MvcEndpoint> endpoints) {
this.endpoints = new HashSet<MvcEndpoint>(endpoints);
// By default the static resource handler mapping is LOWEST_PRECEDENCE - 1
setOrder(LOWEST_PRECEDENCE - 2);
}
......@@ -76,28 +74,20 @@ public class EndpointHandlerMapping extends RequestMappingHandlerMapping impleme
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
if (this.endpoints == null) {
this.endpoints = findEndpointBeans();
if (!this.disabled) {
for (MvcEndpoint endpoint : this.endpoints) {
detectHandlerMethods(endpoint);
}
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private List<Endpoint<?>> findEndpointBeans() {
return new ArrayList(BeanFactoryUtils.beansOfTypeIncludingAncestors(
getApplicationContext(), Endpoint.class).values());
}
/**
* Detects &#64;FrameworkEndpoint annotations in handler beans.
*
* @see org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#isHandler(java.lang.Class)
* Since all handler beans are passed into the constructor there is no need to detect
* anything here
*/
@Override
protected boolean isHandler(Class<?> beanType) {
if (this.disabled) {
return false;
}
return AnnotationUtils.findAnnotation(beanType, FrameworkEndpoint.class) != null;
return false;
}
@Override
......@@ -169,7 +159,7 @@ public class EndpointHandlerMapping extends RequestMappingHandlerMapping impleme
/**
* Return the endpoints
*/
public List<Endpoint<?>> getEndpoints() {
return Collections.unmodifiableList(this.endpoints);
public Set<? extends Endpoint<?>> getEndpoints() {
return this.endpoints;
}
}
......@@ -22,13 +22,13 @@ import org.springframework.core.env.Environment;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PathVariable;
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.bind.annotation.ResponseStatus;
/**
* @author Dave Syer
*/
@FrameworkEndpoint
public class EnvironmentMvcEndpoint extends GenericMvcEndpoint implements
EnvironmentAware {
......@@ -38,7 +38,7 @@ public class EnvironmentMvcEndpoint extends GenericMvcEndpoint implements
super(delegate);
}
@RequestMapping("/{name:.*}")
@RequestMapping(value = "/{name:.*}", method = RequestMethod.GET)
@ResponseBody
public Object value(@PathVariable String name) {
String result = this.environment.getProperty(name);
......
/*
* 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.boot.actuate.endpoint.mvc;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.stereotype.Component;
/**
* @author Dave Syer
*/
@Component
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FrameworkEndpoint {
}
\ No newline at end of file
......@@ -24,7 +24,6 @@ import org.springframework.web.bind.annotation.ResponseBody;
/**
* @author Dave Syer
*/
@FrameworkEndpoint
public class GenericMvcEndpoint implements MvcEndpoint {
private Endpoint<?> delegate;
......@@ -44,4 +43,17 @@ public class GenericMvcEndpoint implements MvcEndpoint {
return this.delegate.getPath();
}
@Override
public boolean isSensitive() {
return this.delegate.isSensitive();
}
@Override
public Class<?> getEndpointType() {
@SuppressWarnings("unchecked")
Class<? extends Endpoint<?>> type = (Class<? extends Endpoint<?>>) this.delegate
.getClass();
return type;
}
}
......@@ -14,12 +14,10 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.endpoint;
package org.springframework.boot.actuate.endpoint.mvc;
import java.util.Map;
import org.springframework.boot.actuate.endpoint.mvc.FrameworkEndpoint;
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
import org.springframework.boot.actuate.web.ErrorController;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.web.bind.annotation.RequestMapping;
......@@ -35,7 +33,6 @@ import org.springframework.web.context.request.RequestContextHolder;
* @author Dave Syer
*/
@ConfigurationProperties(name = "error")
@FrameworkEndpoint
public class ManagementErrorEndpoint implements MvcEndpoint {
private final ErrorController controller;
......@@ -57,4 +54,14 @@ public class ManagementErrorEndpoint implements MvcEndpoint {
public String getPath() {
return this.path;
}
@Override
public boolean isSensitive() {
return false;
}
@Override
public Class<?> getEndpointType() {
return null;
}
}
\ No newline at end of file
......@@ -20,13 +20,13 @@ import org.springframework.boot.actuate.endpoint.MetricsEndpoint;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PathVariable;
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.bind.annotation.ResponseStatus;
/**
* @author Dave Syer
*/
@FrameworkEndpoint
public class MetricsMvcEndpoint extends GenericMvcEndpoint {
private MetricsEndpoint delegate;
......@@ -36,7 +36,7 @@ public class MetricsMvcEndpoint extends GenericMvcEndpoint {
this.delegate = delegate;
}
@RequestMapping("/{name:.*}")
@RequestMapping(value = "/{name:.*}", method = RequestMethod.GET)
@ResponseBody
public Object value(@PathVariable String name) {
Object value = this.delegate.invoke().get(name);
......
......@@ -16,11 +16,19 @@
package org.springframework.boot.actuate.endpoint.mvc;
import org.springframework.boot.actuate.endpoint.Endpoint;
/**
* A strategy for the MVC layer on top of an {@link Endpoint}. Implementations are allowed
* to use <code>@RequestMapping</code> and the full Spring MVC machinery, but should not
* use <code>@Controller</code> or <code>@RequestMapping</code> at the type level (since
* that would lead to a double mapping of paths, once by the regular MVC handler mappings
* and once by the {@link EndpointHandlerMapping}).
*
* @author Dave Syer
*/
public interface MvcEndpoint {
public interface MvcEndpoint extends Endpoint<Object> {
String getPath();
Class<?> getEndpointType();
}
\ No newline at end of file
/*
* 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.boot.actuate.endpoint.mvc;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.actuate.endpoint.Endpoint;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* A registry for all {@link MvcEndpoint} beans, and a factory for a set of generic ones
* wrapping existing {@link Endpoint} instances that are not already exposed as MVC
* endpoints.
*
* @author Dave Syer
*/
@Component
public class MvcEndpoints implements ApplicationContextAware, InitializingBean {
private ApplicationContext applicationContext;
private Set<MvcEndpoint> endpoints = new HashSet<MvcEndpoint>();
private Set<Class<?>> customTypes;
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public void afterPropertiesSet() throws Exception {
Collection<MvcEndpoint> existing = this.applicationContext.getBeansOfType(
MvcEndpoint.class).values();
this.endpoints.addAll(existing);
this.customTypes = findEndpointClasses(existing);
@SuppressWarnings("rawtypes")
Collection<Endpoint> delegates = this.applicationContext.getBeansOfType(
Endpoint.class).values();
for (Endpoint<?> endpoint : delegates) {
if (isGenericEndpoint(endpoint.getClass())) {
this.endpoints.add(new GenericMvcEndpoint(endpoint));
}
}
}
private Set<Class<?>> findEndpointClasses(Collection<MvcEndpoint> existing) {
Set<Class<?>> types = new HashSet<Class<?>>();
for (MvcEndpoint endpoint : existing) {
Class<?> type = endpoint.getEndpointType();
if (type != null) {
types.add(type);
}
}
return types;
}
public Set<? extends MvcEndpoint> getEndpoints() {
return this.endpoints;
}
private boolean isGenericEndpoint(Class<?> type) {
return !this.customTypes.contains(type)
&& !MvcEndpoint.class.isAssignableFrom(type);
}
}
\ No newline at end of file
......@@ -24,7 +24,6 @@ import org.springframework.web.bind.annotation.ResponseBody;
/**
* @author Dave Syer
*/
@FrameworkEndpoint
public class ShutdownMvcEndpoint extends GenericMvcEndpoint {
public ShutdownMvcEndpoint(ShutdownEndpoint delegate) {
......
......@@ -24,8 +24,8 @@ import java.nio.charset.Charset;
import org.junit.After;
import org.junit.Test;
import org.springframework.boot.TestUtils;
import org.springframework.boot.actuate.endpoint.AbstractEndpoint;
import org.springframework.boot.actuate.endpoint.mvc.FrameworkEndpoint;
import org.springframework.boot.actuate.endpoint.Endpoint;
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
import org.springframework.boot.actuate.properties.ManagementServerProperties;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration;
......@@ -240,20 +240,29 @@ public class EndpointWebMvcAutoConfigurationTests {
}
@FrameworkEndpoint
public static class TestEndpoint extends AbstractEndpoint<String> {
public static class TestEndpoint implements MvcEndpoint {
public TestEndpoint() {
super("/endpoint", false, true);
}
@Override
@RequestMapping
@ResponseBody
public String invoke() {
return "endpointoutput";
}
@Override
public String getPath() {
return "/endpoint";
}
@Override
public boolean isSensitive() {
return true;
}
@Override
public Class<?> getEndpointType() {
return Endpoint.class;
}
}
}
......@@ -17,7 +17,6 @@
package org.springframework.boot.actuate.endpoint;
import org.junit.Test;
import org.springframework.boot.actuate.endpoint.EnvironmentEndpoint;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
......
......@@ -17,6 +17,7 @@
package org.springframework.boot.actuate.endpoint.mvc;
import java.lang.reflect.Method;
import java.util.Arrays;
import org.junit.Before;
import org.junit.Test;
......@@ -44,14 +45,10 @@ import static org.junit.Assert.assertThat;
public class EndpointHandlerMappingTests {
private StaticApplicationContext context = new StaticApplicationContext();
private EndpointHandlerMapping mapping = new EndpointHandlerMapping();
private Method method;
@Before
public void init() throws Exception {
this.context.getDefaultListableBeanFactory().registerSingleton("mapping",
this.mapping);
this.mapping.setApplicationContext(this.context);
this.method = ReflectionUtils.findMethod(TestMvcEndpoint.class, "invoke");
}
......@@ -59,18 +56,17 @@ public class EndpointHandlerMappingTests {
public void withoutPrefix() throws Exception {
TestMvcEndpoint endpointA = new TestMvcEndpoint(new TestEndpoint("/a"));
TestMvcEndpoint endpointB = new TestMvcEndpoint(new TestEndpoint("/b"));
this.context.getDefaultListableBeanFactory().registerSingleton(
endpointA.getPath(), endpointA);
this.context.getDefaultListableBeanFactory().registerSingleton(
endpointB.getPath(), endpointB);
this.mapping.afterPropertiesSet();
assertThat(this.mapping.getHandler(new MockHttpServletRequest("GET", "/a"))
EndpointHandlerMapping mapping = new EndpointHandlerMapping(Arrays.asList(
endpointA, endpointB));
mapping.setApplicationContext(this.context);
mapping.afterPropertiesSet();
assertThat(mapping.getHandler(new MockHttpServletRequest("GET", "/a"))
.getHandler(),
equalTo((Object) new HandlerMethod(endpointA, this.method)));
assertThat(this.mapping.getHandler(new MockHttpServletRequest("GET", "/b"))
assertThat(mapping.getHandler(new MockHttpServletRequest("GET", "/b"))
.getHandler(),
equalTo((Object) new HandlerMethod(endpointB, this.method)));
assertThat(this.mapping.getHandler(new MockHttpServletRequest("GET", "/c")),
assertThat(mapping.getHandler(new MockHttpServletRequest("GET", "/c")),
nullValue());
}
......@@ -78,59 +74,62 @@ public class EndpointHandlerMappingTests {
public void withPrefix() throws Exception {
TestMvcEndpoint endpointA = new TestMvcEndpoint(new TestEndpoint("/a"));
TestMvcEndpoint endpointB = new TestMvcEndpoint(new TestEndpoint("/b"));
this.context.getDefaultListableBeanFactory().registerSingleton(
endpointA.getPath(), endpointA);
this.context.getDefaultListableBeanFactory().registerSingleton(
endpointB.getPath(), endpointB);
this.mapping.setPrefix("/a");
this.mapping.afterPropertiesSet();
assertThat(this.mapping.getHandler(new MockHttpServletRequest("GET", "/a/a"))
EndpointHandlerMapping mapping = new EndpointHandlerMapping(Arrays.asList(
endpointA, endpointB));
mapping.setApplicationContext(this.context);
mapping.setPrefix("/a");
mapping.afterPropertiesSet();
assertThat(mapping.getHandler(new MockHttpServletRequest("GET", "/a/a"))
.getHandler(),
equalTo((Object) new HandlerMethod(endpointA, this.method)));
assertThat(this.mapping.getHandler(new MockHttpServletRequest("GET", "/a/b"))
assertThat(mapping.getHandler(new MockHttpServletRequest("GET", "/a/b"))
.getHandler(),
equalTo((Object) new HandlerMethod(endpointB, this.method)));
assertThat(this.mapping.getHandler(new MockHttpServletRequest("GET", "/a")),
assertThat(mapping.getHandler(new MockHttpServletRequest("GET", "/a")),
nullValue());
}
@Test(expected = HttpRequestMethodNotSupportedException.class)
public void onlyGetHttpMethodForNonActionEndpoints() throws Exception {
TestMvcEndpoint endpoint = new TestActionEndpoint(new TestEndpoint("/a"));
this.context.getDefaultListableBeanFactory().registerSingleton(
endpoint.getPath(), endpoint);
this.mapping.afterPropertiesSet();
assertNotNull(this.mapping.getHandler(new MockHttpServletRequest("GET", "/a")));
assertNull(this.mapping.getHandler(new MockHttpServletRequest("POST", "/a")));
TestActionEndpoint endpoint = new TestActionEndpoint(new TestEndpoint("/a"));
EndpointHandlerMapping mapping = new EndpointHandlerMapping(
Arrays.asList(endpoint));
mapping.setApplicationContext(this.context);
mapping.afterPropertiesSet();
assertNotNull(mapping.getHandler(new MockHttpServletRequest("GET", "/a")));
assertNull(mapping.getHandler(new MockHttpServletRequest("POST", "/a")));
}
@Test
public void postHttpMethodForActionEndpoints() throws Exception {
TestMvcEndpoint endpoint = new TestActionEndpoint(new TestEndpoint("/a"));
this.context.getDefaultListableBeanFactory().registerSingleton(
endpoint.getPath(), endpoint);
this.mapping.afterPropertiesSet();
assertNotNull(this.mapping.getHandler(new MockHttpServletRequest("POST", "/a")));
TestActionEndpoint endpoint = new TestActionEndpoint(new TestEndpoint("/a"));
EndpointHandlerMapping mapping = new EndpointHandlerMapping(
Arrays.asList(endpoint));
mapping.setApplicationContext(this.context);
mapping.afterPropertiesSet();
assertNotNull(mapping.getHandler(new MockHttpServletRequest("POST", "/a")));
}
@Test(expected = HttpRequestMethodNotSupportedException.class)
public void onlyPostHttpMethodForActionEndpoints() throws Exception {
TestMvcEndpoint endpoint = new TestActionEndpoint(new TestEndpoint("/a"));
this.context.getDefaultListableBeanFactory().registerSingleton(
endpoint.getPath(), endpoint);
this.mapping.afterPropertiesSet();
assertNotNull(this.mapping.getHandler(new MockHttpServletRequest("POST", "/a")));
assertNull(this.mapping.getHandler(new MockHttpServletRequest("GET", "/a")));
TestActionEndpoint endpoint = new TestActionEndpoint(new TestEndpoint("/a"));
EndpointHandlerMapping mapping = new EndpointHandlerMapping(
Arrays.asList(endpoint));
mapping.setApplicationContext(this.context);
mapping.afterPropertiesSet();
assertNotNull(mapping.getHandler(new MockHttpServletRequest("POST", "/a")));
assertNull(mapping.getHandler(new MockHttpServletRequest("GET", "/a")));
}
@Test
public void disabled() throws Exception {
TestMvcEndpoint endpoint = new TestMvcEndpoint(new TestEndpoint("/a"));
this.context.getDefaultListableBeanFactory().registerSingleton(
endpoint.getPath(), endpoint);
this.mapping.setDisabled(true);
this.mapping.afterPropertiesSet();
assertThat(this.mapping.getHandler(new MockHttpServletRequest("GET", "/a")),
EndpointHandlerMapping mapping = new EndpointHandlerMapping(
Arrays.asList(endpoint));
mapping.setDisabled(true);
mapping.setApplicationContext(this.context);
mapping.afterPropertiesSet();
assertThat(mapping.getHandler(new MockHttpServletRequest("GET", "/a")),
nullValue());
}
......@@ -141,14 +140,12 @@ public class EndpointHandlerMappingTests {
}
@Override
@RequestMapping(method = RequestMethod.GET)
public Object invoke() {
return null;
}
}
@FrameworkEndpoint
private static class TestMvcEndpoint extends GenericMvcEndpoint {
public TestMvcEndpoint(TestEndpoint delegate) {
......@@ -157,8 +154,7 @@ public class EndpointHandlerMappingTests {
}
@FrameworkEndpoint
private static class TestActionEndpoint extends TestMvcEndpoint {
private static class TestActionEndpoint extends GenericMvcEndpoint {
public TestActionEndpoint(TestEndpoint delegate) {
super(delegate);
......@@ -169,6 +165,7 @@ public class EndpointHandlerMappingTests {
public Object invoke() {
return null;
}
}
}
/*
* 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.boot.actuate.endpoint.mvc;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.TestUtils;
import org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration;
import org.springframework.boot.actuate.endpoint.EnvironmentEndpoint;
import org.springframework.boot.actuate.endpoint.mvc.EnvironmentMvcEndpointTests.TestConfiguration;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalToIgnoringCase;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* @author Dave Syer
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = { TestConfiguration.class })
@WebAppConfiguration
public class EnvironmentMvcEndpointTests {
@Autowired
private WebApplicationContext context;
private MockMvc mvc;
@Before
public void setUp() {
this.mvc = MockMvcBuilders.webAppContextSetup(this.context).build();
TestUtils.addEnviroment((ConfigurableApplicationContext) this.context, "foo:bar");
}
@Test
public void home() throws Exception {
this.mvc.perform(get("/env")).andExpect(status().isOk())
.andExpect(content().string(containsString("systemProperties")));
}
@Test
public void sub() throws Exception {
this.mvc.perform(get("/env/foo")).andExpect(status().isOk())
.andExpect(content().string(equalToIgnoringCase("bar")));
}
@Import(EndpointWebMvcAutoConfiguration.class)
@EnableWebMvc
@Configuration
public static class TestConfiguration {
@Bean
public EnvironmentEndpoint endpoint() {
return new EnvironmentEndpoint();
}
@Bean
public EnvironmentMvcEndpoint mvcEndpoint() {
return new EnvironmentMvcEndpoint(endpoint());
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment