Add CloudFoundryDiscoveryMvcEndpoint
Update Cloud Foundry support with a discovery endpoint that shows what endpoints are available. See gh-7108
This commit is contained in:
		
							parent
							
								
									7afb161fcf
								
							
						
					
					
						commit
						ab81d993e6
					
				| 
						 | 
					@ -79,7 +79,7 @@ public class EndpointWebMvcManagementContextConfiguration {
 | 
				
			||||||
	@Bean
 | 
						@Bean
 | 
				
			||||||
	@ConditionalOnMissingBean
 | 
						@ConditionalOnMissingBean
 | 
				
			||||||
	public EndpointHandlerMapping endpointHandlerMapping() {
 | 
						public EndpointHandlerMapping endpointHandlerMapping() {
 | 
				
			||||||
		Set<? extends MvcEndpoint> endpoints = mvcEndpoints().getEndpoints();
 | 
							Set<MvcEndpoint> endpoints = mvcEndpoints().getEndpoints();
 | 
				
			||||||
		CorsConfiguration corsConfiguration = getCorsConfiguration(this.corsProperties);
 | 
							CorsConfiguration corsConfiguration = getCorsConfiguration(this.corsProperties);
 | 
				
			||||||
		EndpointHandlerMapping mapping = new EndpointHandlerMapping(endpoints,
 | 
							EndpointHandlerMapping mapping = new EndpointHandlerMapping(endpoints,
 | 
				
			||||||
				corsConfiguration);
 | 
									corsConfiguration);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -406,8 +406,7 @@ public class ManagementWebSecurityAutoConfiguration {
 | 
				
			||||||
			EndpointHandlerMapping endpointHandlerMapping = null;
 | 
								EndpointHandlerMapping endpointHandlerMapping = null;
 | 
				
			||||||
			ApplicationContext context = this.contextResolver.getApplicationContext();
 | 
								ApplicationContext context = this.contextResolver.getApplicationContext();
 | 
				
			||||||
			if (context.getBeanNamesForType(EndpointHandlerMapping.class).length > 0) {
 | 
								if (context.getBeanNamesForType(EndpointHandlerMapping.class).length > 0) {
 | 
				
			||||||
				endpointHandlerMapping = context.getBean("endpointHandlerMapping",
 | 
									endpointHandlerMapping = context.getBean(EndpointHandlerMapping.class);
 | 
				
			||||||
						EndpointHandlerMapping.class);
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if (endpointHandlerMapping == null) {
 | 
								if (endpointHandlerMapping == null) {
 | 
				
			||||||
				// Maybe there are actually no endpoints (e.g. management.port=-1)
 | 
									// Maybe there are actually no endpoints (e.g. management.port=-1)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,86 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright 2012-2016 the original author or authors.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					 * you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					 * You may obtain a copy of the License at
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *      http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					 * See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					 * limitations under the License.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package org.springframework.boot.actuate.cloudfoundry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.Collections;
 | 
				
			||||||
 | 
					import java.util.LinkedHashMap;
 | 
				
			||||||
 | 
					import java.util.Map;
 | 
				
			||||||
 | 
					import java.util.Set;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import javax.servlet.http.HttpServletRequest;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.springframework.boot.actuate.endpoint.mvc.AbstractMvcEndpoint;
 | 
				
			||||||
 | 
					import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
 | 
				
			||||||
 | 
					import org.springframework.boot.actuate.endpoint.mvc.NamedMvcEndpoint;
 | 
				
			||||||
 | 
					import org.springframework.http.MediaType;
 | 
				
			||||||
 | 
					import org.springframework.web.bind.annotation.RequestMapping;
 | 
				
			||||||
 | 
					import org.springframework.web.bind.annotation.ResponseBody;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * {@link MvcEndpoint} to expose HAL-formatted JSON for Cloud Foundry specific actuator
 | 
				
			||||||
 | 
					 * endpoints.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @author Madhura Bhave
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class CloudFoundryDiscoveryMvcEndpoint extends AbstractMvcEndpoint {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private final Set<NamedMvcEndpoint> endpoints;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						CloudFoundryDiscoveryMvcEndpoint(Set<NamedMvcEndpoint> endpoints) {
 | 
				
			||||||
 | 
							super("", false);
 | 
				
			||||||
 | 
							this.endpoints = endpoints;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE)
 | 
				
			||||||
 | 
						@ResponseBody
 | 
				
			||||||
 | 
						public Map<String, Map<String, Link>> links(HttpServletRequest request) {
 | 
				
			||||||
 | 
							Map<String, Link> links = new LinkedHashMap<String, Link>();
 | 
				
			||||||
 | 
							String url = request.getRequestURL().toString();
 | 
				
			||||||
 | 
							if (url.endsWith("/")) {
 | 
				
			||||||
 | 
								url = url.substring(0, url.length() - 1);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							links.put("self", Link.withHref(url));
 | 
				
			||||||
 | 
							for (NamedMvcEndpoint endpoint : this.endpoints) {
 | 
				
			||||||
 | 
								links.put(endpoint.getName(), Link.withHref(url + "/" + endpoint.getName()));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return Collections.singletonMap("_links", links);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Details for a link in the HAL response.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						static class Link {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							private String href;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public String getHref() {
 | 
				
			||||||
 | 
								return this.href;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public void setHref(String href) {
 | 
				
			||||||
 | 
								this.href = href;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							static Link withHref(Object href) {
 | 
				
			||||||
 | 
								Link link = new Link();
 | 
				
			||||||
 | 
								link.setHref(href.toString());
 | 
				
			||||||
 | 
								return link;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -19,6 +19,7 @@ package org.springframework.boot.actuate.cloudfoundry;
 | 
				
			||||||
import java.util.ArrayList;
 | 
					import java.util.ArrayList;
 | 
				
			||||||
import java.util.Arrays;
 | 
					import java.util.Arrays;
 | 
				
			||||||
import java.util.Collection;
 | 
					import java.util.Collection;
 | 
				
			||||||
 | 
					import java.util.Iterator;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
import java.util.Set;
 | 
					import java.util.Set;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,7 +27,8 @@ import javax.servlet.http.HttpServletRequest;
 | 
				
			||||||
import javax.servlet.http.HttpServletResponse;
 | 
					import javax.servlet.http.HttpServletResponse;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import org.springframework.boot.actuate.endpoint.Endpoint;
 | 
					import org.springframework.boot.actuate.endpoint.Endpoint;
 | 
				
			||||||
import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping;
 | 
					import org.springframework.boot.actuate.endpoint.mvc.AbstractEndpointHandlerMapping;
 | 
				
			||||||
 | 
					import org.springframework.boot.actuate.endpoint.mvc.HalJsonMvcEndpoint;
 | 
				
			||||||
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
 | 
					import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
 | 
				
			||||||
import org.springframework.boot.actuate.endpoint.mvc.NamedMvcEndpoint;
 | 
					import org.springframework.boot.actuate.endpoint.mvc.NamedMvcEndpoint;
 | 
				
			||||||
import org.springframework.web.cors.CorsConfiguration;
 | 
					import org.springframework.web.cors.CorsConfiguration;
 | 
				
			||||||
| 
						 | 
					@ -40,7 +42,8 @@ import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Madhura Bhave
 | 
					 * @author Madhura Bhave
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
class CloudFoundryEndpointHandlerMapping extends EndpointHandlerMapping {
 | 
					class CloudFoundryEndpointHandlerMapping
 | 
				
			||||||
 | 
							extends AbstractEndpointHandlerMapping<NamedMvcEndpoint> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	CloudFoundryEndpointHandlerMapping(Collection<? extends NamedMvcEndpoint> endpoints) {
 | 
						CloudFoundryEndpointHandlerMapping(Collection<? extends NamedMvcEndpoint> endpoints) {
 | 
				
			||||||
		super(endpoints);
 | 
							super(endpoints);
 | 
				
			||||||
| 
						 | 
					@ -51,6 +54,23 @@ class CloudFoundryEndpointHandlerMapping extends EndpointHandlerMapping {
 | 
				
			||||||
		super(endpoints, corsConfiguration);
 | 
							super(endpoints, corsConfiguration);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						protected void postProcessEndpoints(Set<NamedMvcEndpoint> endpoints) {
 | 
				
			||||||
 | 
							super.postProcessEndpoints(endpoints);
 | 
				
			||||||
 | 
							Iterator<NamedMvcEndpoint> iterator = endpoints.iterator();
 | 
				
			||||||
 | 
							while (iterator.hasNext()) {
 | 
				
			||||||
 | 
								if (iterator.next() instanceof HalJsonMvcEndpoint) {
 | 
				
			||||||
 | 
									iterator.remove();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						public void afterPropertiesSet() {
 | 
				
			||||||
 | 
							super.afterPropertiesSet();
 | 
				
			||||||
 | 
							detectHandlerMethods(new CloudFoundryDiscoveryMvcEndpoint(getEndpoints()));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Override
 | 
						@Override
 | 
				
			||||||
	protected String getPath(MvcEndpoint endpoint) {
 | 
						protected String getPath(MvcEndpoint endpoint) {
 | 
				
			||||||
		if (endpoint instanceof NamedMvcEndpoint) {
 | 
							if (endpoint instanceof NamedMvcEndpoint) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,235 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright 2012-2015 the original author or authors.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					 * you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					 * You may obtain a copy of the License at
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *      http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					 * See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					 * limitations under the License.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package org.springframework.boot.actuate.endpoint.mvc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.lang.reflect.Method;
 | 
				
			||||||
 | 
					import java.util.ArrayList;
 | 
				
			||||||
 | 
					import java.util.Collection;
 | 
				
			||||||
 | 
					import java.util.Collections;
 | 
				
			||||||
 | 
					import java.util.HashSet;
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					import java.util.Set;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.springframework.boot.actuate.endpoint.Endpoint;
 | 
				
			||||||
 | 
					import org.springframework.context.ApplicationContext;
 | 
				
			||||||
 | 
					import org.springframework.util.Assert;
 | 
				
			||||||
 | 
					import org.springframework.util.ObjectUtils;
 | 
				
			||||||
 | 
					import org.springframework.util.StringUtils;
 | 
				
			||||||
 | 
					import org.springframework.web.cors.CorsConfiguration;
 | 
				
			||||||
 | 
					import org.springframework.web.servlet.HandlerMapping;
 | 
				
			||||||
 | 
					import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
 | 
				
			||||||
 | 
					import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
 | 
				
			||||||
 | 
					import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * {@link HandlerMapping} to map {@link Endpoint}s to URLs via {@link Endpoint#getId()}.
 | 
				
			||||||
 | 
					 * The semantics of {@code @RequestMapping} should be identical to a normal
 | 
				
			||||||
 | 
					 * {@code @Controller}, but the endpoints should not be annotated as {@code @Controller}
 | 
				
			||||||
 | 
					 * (otherwise they will be mapped by the normal MVC mechanisms).
 | 
				
			||||||
 | 
					 * <p>
 | 
				
			||||||
 | 
					 * One of the aims of the mapping is to support endpoints that work as HTTP endpoints but
 | 
				
			||||||
 | 
					 * can still provide useful service interfaces when there is no HTTP server (and no Spring
 | 
				
			||||||
 | 
					 * MVC on the classpath). Note that any endpoints having method signatures will break in a
 | 
				
			||||||
 | 
					 * non-servlet environment.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param <E> The endpoint type
 | 
				
			||||||
 | 
					 * @author Phillip Webb
 | 
				
			||||||
 | 
					 * @author Christian Dupuis
 | 
				
			||||||
 | 
					 * @author Dave Syer
 | 
				
			||||||
 | 
					 * @author Madhura Bhave
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class AbstractEndpointHandlerMapping<E extends MvcEndpoint>
 | 
				
			||||||
 | 
							extends RequestMappingHandlerMapping {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private final Set<E> endpoints;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private final CorsConfiguration corsConfiguration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private String prefix = "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private boolean disabled = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Create a new {@link AbstractEndpointHandlerMapping} instance. All {@link Endpoint}s
 | 
				
			||||||
 | 
						 * will be detected from the {@link ApplicationContext}. The endpoints will not accept
 | 
				
			||||||
 | 
						 * CORS requests.
 | 
				
			||||||
 | 
						 * @param endpoints the endpoints
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public AbstractEndpointHandlerMapping(Collection<? extends E> endpoints) {
 | 
				
			||||||
 | 
							this(endpoints, null);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Create a new {@link AbstractEndpointHandlerMapping} instance. All {@link Endpoint}s
 | 
				
			||||||
 | 
						 * will be detected from the {@link ApplicationContext}. The endpoints will accepts
 | 
				
			||||||
 | 
						 * CORS requests based on the given {@code corsConfiguration}.
 | 
				
			||||||
 | 
						 * @param endpoints the endpoints
 | 
				
			||||||
 | 
						 * @param corsConfiguration the CORS configuration for the endpoints
 | 
				
			||||||
 | 
						 * @since 1.3.0
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public AbstractEndpointHandlerMapping(Collection<? extends E> endpoints,
 | 
				
			||||||
 | 
								CorsConfiguration corsConfiguration) {
 | 
				
			||||||
 | 
							this.endpoints = new HashSet<E>(endpoints);
 | 
				
			||||||
 | 
							postProcessEndpoints(this.endpoints);
 | 
				
			||||||
 | 
							this.corsConfiguration = corsConfiguration;
 | 
				
			||||||
 | 
							// By default the static resource handler mapping is LOWEST_PRECEDENCE - 1
 | 
				
			||||||
 | 
							// and the RequestMappingHandlerMapping is 0 (we ideally want to be before both)
 | 
				
			||||||
 | 
							setOrder(-100);
 | 
				
			||||||
 | 
							setUseSuffixPatternMatch(false);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Post process the endpoint setting before they are used. Subclasses can add or
 | 
				
			||||||
 | 
						 * modify the endpoints as necessary.
 | 
				
			||||||
 | 
						 * @param endpoints the endpoints to post process
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						protected void postProcessEndpoints(Set<E> endpoints) {
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						public void afterPropertiesSet() {
 | 
				
			||||||
 | 
							super.afterPropertiesSet();
 | 
				
			||||||
 | 
							if (!this.disabled) {
 | 
				
			||||||
 | 
								for (MvcEndpoint endpoint : this.endpoints) {
 | 
				
			||||||
 | 
									detectHandlerMethods(endpoint);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Since all handler beans are passed into the constructor there is no need to detect
 | 
				
			||||||
 | 
						 * anything here.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						protected boolean isHandler(Class<?> beanType) {
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						@Deprecated
 | 
				
			||||||
 | 
						protected void registerHandlerMethod(Object handler, Method method,
 | 
				
			||||||
 | 
								RequestMappingInfo mapping) {
 | 
				
			||||||
 | 
							if (mapping == null) {
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							String[] patterns = getPatterns(handler, mapping);
 | 
				
			||||||
 | 
							if (!ObjectUtils.isEmpty(patterns)) {
 | 
				
			||||||
 | 
								super.registerHandlerMethod(handler, method,
 | 
				
			||||||
 | 
										withNewPatterns(mapping, patterns));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private String[] getPatterns(Object handler, RequestMappingInfo mapping) {
 | 
				
			||||||
 | 
							if (handler instanceof String) {
 | 
				
			||||||
 | 
								handler = getApplicationContext().getBean((String) handler);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							Assert.state(handler instanceof MvcEndpoint, "Only MvcEndpoints are supported");
 | 
				
			||||||
 | 
							String path = getPath((MvcEndpoint) handler);
 | 
				
			||||||
 | 
							return (path == null ? null : getEndpointPatterns(path, mapping));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Return the path that should be used to map the given {@link MvcEndpoint}.
 | 
				
			||||||
 | 
						 * @param endpoint the endpoint to map
 | 
				
			||||||
 | 
						 * @return the path to use for the endpoint or {@code null} if no mapping is required
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						protected String getPath(MvcEndpoint endpoint) {
 | 
				
			||||||
 | 
							return endpoint.getPath();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private String[] getEndpointPatterns(String path, RequestMappingInfo mapping) {
 | 
				
			||||||
 | 
							String patternPrefix = StringUtils.hasText(this.prefix) ? this.prefix + path
 | 
				
			||||||
 | 
									: path;
 | 
				
			||||||
 | 
							Set<String> defaultPatterns = mapping.getPatternsCondition().getPatterns();
 | 
				
			||||||
 | 
							if (defaultPatterns.isEmpty()) {
 | 
				
			||||||
 | 
								return new String[] { patternPrefix, patternPrefix + ".json" };
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							List<String> patterns = new ArrayList<String>(defaultPatterns);
 | 
				
			||||||
 | 
							for (int i = 0; i < patterns.size(); i++) {
 | 
				
			||||||
 | 
								patterns.set(i, patternPrefix + patterns.get(i));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return patterns.toArray(new String[patterns.size()]);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private RequestMappingInfo withNewPatterns(RequestMappingInfo mapping,
 | 
				
			||||||
 | 
								String[] patternStrings) {
 | 
				
			||||||
 | 
							PatternsRequestCondition patterns = new PatternsRequestCondition(patternStrings,
 | 
				
			||||||
 | 
									null, null, useSuffixPatternMatch(), useTrailingSlashMatch(), null);
 | 
				
			||||||
 | 
							return new RequestMappingInfo(patterns, mapping.getMethodsCondition(),
 | 
				
			||||||
 | 
									mapping.getParamsCondition(), mapping.getHeadersCondition(),
 | 
				
			||||||
 | 
									mapping.getConsumesCondition(), mapping.getProducesCondition(),
 | 
				
			||||||
 | 
									mapping.getCustomCondition());
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Set the prefix used in mappings.
 | 
				
			||||||
 | 
						 * @param prefix the prefix
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public void setPrefix(String prefix) {
 | 
				
			||||||
 | 
							Assert.isTrue("".equals(prefix) || StringUtils.startsWithIgnoreCase(prefix, "/"),
 | 
				
			||||||
 | 
									"prefix must start with '/'");
 | 
				
			||||||
 | 
							this.prefix = prefix;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Get the prefix used in mappings.
 | 
				
			||||||
 | 
						 * @return the prefix
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public String getPrefix() {
 | 
				
			||||||
 | 
							return this.prefix;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Get the path of the endpoint.
 | 
				
			||||||
 | 
						 * @param endpoint the endpoint
 | 
				
			||||||
 | 
						 * @return the path used in mappings
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public String getPath(String endpoint) {
 | 
				
			||||||
 | 
							return this.prefix + endpoint;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Sets if this mapping is disabled.
 | 
				
			||||||
 | 
						 * @param disabled if the mapping is disabled
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public void setDisabled(boolean disabled) {
 | 
				
			||||||
 | 
							this.disabled = disabled;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Returns if this mapping is disabled.
 | 
				
			||||||
 | 
						 * @return if the mapping is disabled
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public boolean isDisabled() {
 | 
				
			||||||
 | 
							return this.disabled;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Return the endpoints.
 | 
				
			||||||
 | 
						 * @return the endpoints
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public Set<E> getEndpoints() {
 | 
				
			||||||
 | 
							return Collections.unmodifiableSet(this.endpoints);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						protected CorsConfiguration initCorsConfiguration(Object handler, Method method,
 | 
				
			||||||
 | 
								RequestMappingInfo mappingInfo) {
 | 
				
			||||||
 | 
							return this.corsConfiguration;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -16,24 +16,12 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package org.springframework.boot.actuate.endpoint.mvc;
 | 
					package org.springframework.boot.actuate.endpoint.mvc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.lang.reflect.Method;
 | 
					 | 
				
			||||||
import java.util.ArrayList;
 | 
					 | 
				
			||||||
import java.util.Collection;
 | 
					import java.util.Collection;
 | 
				
			||||||
import java.util.Collections;
 | 
					 | 
				
			||||||
import java.util.HashSet;
 | 
					 | 
				
			||||||
import java.util.List;
 | 
					 | 
				
			||||||
import java.util.Set;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import org.springframework.boot.actuate.endpoint.Endpoint;
 | 
					import org.springframework.boot.actuate.endpoint.Endpoint;
 | 
				
			||||||
import org.springframework.context.ApplicationContext;
 | 
					import org.springframework.context.ApplicationContext;
 | 
				
			||||||
import org.springframework.util.Assert;
 | 
					 | 
				
			||||||
import org.springframework.util.ObjectUtils;
 | 
					 | 
				
			||||||
import org.springframework.util.StringUtils;
 | 
					 | 
				
			||||||
import org.springframework.web.cors.CorsConfiguration;
 | 
					import org.springframework.web.cors.CorsConfiguration;
 | 
				
			||||||
import org.springframework.web.servlet.HandlerMapping;
 | 
					import org.springframework.web.servlet.HandlerMapping;
 | 
				
			||||||
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
 | 
					 | 
				
			||||||
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
 | 
					 | 
				
			||||||
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * {@link HandlerMapping} to map {@link Endpoint}s to URLs via {@link Endpoint#getId()}.
 | 
					 * {@link HandlerMapping} to map {@link Endpoint}s to URLs via {@link Endpoint#getId()}.
 | 
				
			||||||
| 
						 | 
					@ -50,15 +38,7 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandl
 | 
				
			||||||
 * @author Christian Dupuis
 | 
					 * @author Christian Dupuis
 | 
				
			||||||
 * @author Dave Syer
 | 
					 * @author Dave Syer
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public class EndpointHandlerMapping extends RequestMappingHandlerMapping {
 | 
					public class EndpointHandlerMapping extends AbstractEndpointHandlerMapping<MvcEndpoint> {
 | 
				
			||||||
 | 
					 | 
				
			||||||
	private final Set<MvcEndpoint> endpoints;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private final CorsConfiguration corsConfiguration;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private String prefix = "";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private boolean disabled = false;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Create a new {@link EndpointHandlerMapping} instance. All {@link Endpoint}s will be
 | 
						 * Create a new {@link EndpointHandlerMapping} instance. All {@link Endpoint}s will be
 | 
				
			||||||
| 
						 | 
					@ -67,7 +47,7 @@ public class EndpointHandlerMapping extends RequestMappingHandlerMapping {
 | 
				
			||||||
	 * @param endpoints the endpoints
 | 
						 * @param endpoints the endpoints
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public EndpointHandlerMapping(Collection<? extends MvcEndpoint> endpoints) {
 | 
						public EndpointHandlerMapping(Collection<? extends MvcEndpoint> endpoints) {
 | 
				
			||||||
		this(endpoints, null);
 | 
							super(endpoints);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
| 
						 | 
					@ -80,144 +60,7 @@ public class EndpointHandlerMapping extends RequestMappingHandlerMapping {
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public EndpointHandlerMapping(Collection<? extends MvcEndpoint> endpoints,
 | 
						public EndpointHandlerMapping(Collection<? extends MvcEndpoint> endpoints,
 | 
				
			||||||
			CorsConfiguration corsConfiguration) {
 | 
								CorsConfiguration corsConfiguration) {
 | 
				
			||||||
		this.endpoints = new HashSet<MvcEndpoint>(endpoints);
 | 
							super(endpoints, corsConfiguration);
 | 
				
			||||||
		this.corsConfiguration = corsConfiguration;
 | 
					 | 
				
			||||||
		// By default the static resource handler mapping is LOWEST_PRECEDENCE - 1
 | 
					 | 
				
			||||||
		// and the RequestMappingHandlerMapping is 0 (we ideally want to be before both)
 | 
					 | 
				
			||||||
		setOrder(-100);
 | 
					 | 
				
			||||||
		setUseSuffixPatternMatch(false);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@Override
 | 
					 | 
				
			||||||
	public void afterPropertiesSet() {
 | 
					 | 
				
			||||||
		super.afterPropertiesSet();
 | 
					 | 
				
			||||||
		if (!this.disabled) {
 | 
					 | 
				
			||||||
			for (MvcEndpoint endpoint : this.endpoints) {
 | 
					 | 
				
			||||||
				detectHandlerMethods(endpoint);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Since all handler beans are passed into the constructor there is no need to detect
 | 
					 | 
				
			||||||
	 * anything here.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	@Override
 | 
					 | 
				
			||||||
	protected boolean isHandler(Class<?> beanType) {
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@Override
 | 
					 | 
				
			||||||
	@Deprecated
 | 
					 | 
				
			||||||
	protected void registerHandlerMethod(Object handler, Method method,
 | 
					 | 
				
			||||||
			RequestMappingInfo mapping) {
 | 
					 | 
				
			||||||
		if (mapping == null) {
 | 
					 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		String[] patterns = getPatterns(handler, mapping);
 | 
					 | 
				
			||||||
		if (!ObjectUtils.isEmpty(patterns)) {
 | 
					 | 
				
			||||||
			super.registerHandlerMethod(handler, method,
 | 
					 | 
				
			||||||
					withNewPatterns(mapping, patterns));
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private String[] getPatterns(Object handler, RequestMappingInfo mapping) {
 | 
					 | 
				
			||||||
		if (handler instanceof String) {
 | 
					 | 
				
			||||||
			handler = getApplicationContext().getBean((String) handler);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		Assert.state(handler instanceof MvcEndpoint, "Only MvcEndpoints are supported");
 | 
					 | 
				
			||||||
		String path = getPath((MvcEndpoint) handler);
 | 
					 | 
				
			||||||
		return (path == null ? null : getEndpointPatterns(path, mapping));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Return the path that should be used to map the given {@link MvcEndpoint}.
 | 
					 | 
				
			||||||
	 * @param endpoint the endpoint to map
 | 
					 | 
				
			||||||
	 * @return the path to use for the endpoint or {@code null} if no mapping is required
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	protected String getPath(MvcEndpoint endpoint) {
 | 
					 | 
				
			||||||
		return endpoint.getPath();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private String[] getEndpointPatterns(String path, RequestMappingInfo mapping) {
 | 
					 | 
				
			||||||
		String patternPrefix = StringUtils.hasText(this.prefix) ? this.prefix + path
 | 
					 | 
				
			||||||
				: path;
 | 
					 | 
				
			||||||
		Set<String> defaultPatterns = mapping.getPatternsCondition().getPatterns();
 | 
					 | 
				
			||||||
		if (defaultPatterns.isEmpty()) {
 | 
					 | 
				
			||||||
			return new String[] { patternPrefix, patternPrefix + ".json" };
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		List<String> patterns = new ArrayList<String>(defaultPatterns);
 | 
					 | 
				
			||||||
		for (int i = 0; i < patterns.size(); i++) {
 | 
					 | 
				
			||||||
			patterns.set(i, patternPrefix + patterns.get(i));
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return patterns.toArray(new String[patterns.size()]);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private RequestMappingInfo withNewPatterns(RequestMappingInfo mapping,
 | 
					 | 
				
			||||||
			String[] patternStrings) {
 | 
					 | 
				
			||||||
		PatternsRequestCondition patterns = new PatternsRequestCondition(patternStrings,
 | 
					 | 
				
			||||||
				null, null, useSuffixPatternMatch(), useTrailingSlashMatch(), null);
 | 
					 | 
				
			||||||
		return new RequestMappingInfo(patterns, mapping.getMethodsCondition(),
 | 
					 | 
				
			||||||
				mapping.getParamsCondition(), mapping.getHeadersCondition(),
 | 
					 | 
				
			||||||
				mapping.getConsumesCondition(), mapping.getProducesCondition(),
 | 
					 | 
				
			||||||
				mapping.getCustomCondition());
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Set the prefix used in mappings.
 | 
					 | 
				
			||||||
	 * @param prefix the prefix
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public void setPrefix(String prefix) {
 | 
					 | 
				
			||||||
		Assert.isTrue("".equals(prefix) || StringUtils.startsWithIgnoreCase(prefix, "/"),
 | 
					 | 
				
			||||||
				"prefix must start with '/'");
 | 
					 | 
				
			||||||
		this.prefix = prefix;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Get the prefix used in mappings.
 | 
					 | 
				
			||||||
	 * @return the prefix
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public String getPrefix() {
 | 
					 | 
				
			||||||
		return this.prefix;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Get the path of the endpoint.
 | 
					 | 
				
			||||||
	 * @param endpoint the endpoint
 | 
					 | 
				
			||||||
	 * @return the path used in mappings
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public String getPath(String endpoint) {
 | 
					 | 
				
			||||||
		return this.prefix + endpoint;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Sets if this mapping is disabled.
 | 
					 | 
				
			||||||
	 * @param disabled if the mapping is disabled
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public void setDisabled(boolean disabled) {
 | 
					 | 
				
			||||||
		this.disabled = disabled;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Returns if this mapping is disabled.
 | 
					 | 
				
			||||||
	 * @return if the mapping is disabled
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public boolean isDisabled() {
 | 
					 | 
				
			||||||
		return this.disabled;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Return the endpoints.
 | 
					 | 
				
			||||||
	 * @return the endpoints
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public Set<MvcEndpoint> getEndpoints() {
 | 
					 | 
				
			||||||
		return Collections.unmodifiableSet(this.endpoints);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@Override
 | 
					 | 
				
			||||||
	protected CorsConfiguration initCorsConfiguration(Object handler, Method method,
 | 
					 | 
				
			||||||
			RequestMappingInfo mappingInfo) {
 | 
					 | 
				
			||||||
		return this.corsConfiguration;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -89,19 +89,20 @@ public class MvcEndpoints implements ApplicationContextAware, InitializingBean {
 | 
				
			||||||
		return types;
 | 
							return types;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public Set<? extends MvcEndpoint> getEndpoints() {
 | 
						public Set<MvcEndpoint> getEndpoints() {
 | 
				
			||||||
		return this.endpoints;
 | 
							return this.endpoints;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Return the endpoints of the specified type.
 | 
						 * Return the endpoints of the specified type.
 | 
				
			||||||
	 * @param <E>  the Class type of the endpoints to be returned
 | 
						 * @param <E> the Class type of the endpoints to be returned
 | 
				
			||||||
	 * @param type the endpoint type
 | 
						 * @param type the endpoint type
 | 
				
			||||||
	 * @return the endpoints
 | 
						 * @return the endpoints
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
 | 
						@SuppressWarnings("unchecked")
 | 
				
			||||||
	public <E extends MvcEndpoint> Set<E> getEndpoints(Class<E> type) {
 | 
						public <E extends MvcEndpoint> Set<E> getEndpoints(Class<E> type) {
 | 
				
			||||||
		Set<E> result = new HashSet<E>(this.endpoints.size());
 | 
							Set<E> result = new HashSet<E>(this.endpoints.size());
 | 
				
			||||||
		for (MvcEndpoint candidate: this.endpoints) {
 | 
							for (MvcEndpoint candidate : this.endpoints) {
 | 
				
			||||||
			if (type.isInstance(candidate)) {
 | 
								if (type.isInstance(candidate)) {
 | 
				
			||||||
				result.add((E) candidate);
 | 
									result.add((E) candidate);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,100 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright 2012-2016 the original author or authors.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					 * you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					 * You may obtain a copy of the License at
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *      http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					 * See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					 * limitations under the License.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package org.springframework.boot.actuate.cloudfoundry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.LinkedHashSet;
 | 
				
			||||||
 | 
					import java.util.Map;
 | 
				
			||||||
 | 
					import java.util.Set;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.junit.Before;
 | 
				
			||||||
 | 
					import org.junit.Test;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.springframework.boot.actuate.endpoint.AbstractEndpoint;
 | 
				
			||||||
 | 
					import org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter;
 | 
				
			||||||
 | 
					import org.springframework.boot.actuate.endpoint.mvc.NamedMvcEndpoint;
 | 
				
			||||||
 | 
					import org.springframework.mock.web.MockHttpServletRequest;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import static org.assertj.core.api.Assertions.assertThat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Tests for {@link CloudFoundryDiscoveryMvcEndpoint}.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @author Madhura Bhave
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class CloudFoundryDiscoveryMvcEndpointTests {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private CloudFoundryDiscoveryMvcEndpoint endpoint;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Before
 | 
				
			||||||
 | 
						public void setup() {
 | 
				
			||||||
 | 
							NamedMvcEndpoint testMvcEndpoint = new TestMvcEndpoint(new TestEndpoint("a"));
 | 
				
			||||||
 | 
							Set<NamedMvcEndpoint> endpoints = new LinkedHashSet<NamedMvcEndpoint>();
 | 
				
			||||||
 | 
							endpoints.add(testMvcEndpoint);
 | 
				
			||||||
 | 
							this.endpoint = new CloudFoundryDiscoveryMvcEndpoint(endpoints);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Test
 | 
				
			||||||
 | 
						public void cloudfoundryHalJsonEndpointHasEmptyPath() throws Exception {
 | 
				
			||||||
 | 
							assertThat(this.endpoint.getPath()).isEmpty();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Test
 | 
				
			||||||
 | 
						public void linksResponseWhenRequestUriHasNoTrailingSlash() throws Exception {
 | 
				
			||||||
 | 
							MockHttpServletRequest request = new MockHttpServletRequest("GET",
 | 
				
			||||||
 | 
									"/cloudfoundryapplication");
 | 
				
			||||||
 | 
							Map<String, CloudFoundryDiscoveryMvcEndpoint.Link> links = this.endpoint
 | 
				
			||||||
 | 
									.links(request).get("_links");
 | 
				
			||||||
 | 
							assertThat(links.get("self").getHref())
 | 
				
			||||||
 | 
									.isEqualTo("http://localhost/cloudfoundryapplication");
 | 
				
			||||||
 | 
							assertThat(links.get("a").getHref())
 | 
				
			||||||
 | 
									.isEqualTo("http://localhost/cloudfoundryapplication/a");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Test
 | 
				
			||||||
 | 
						public void linksResponseWhenRequestUriHasTrailingSlash() throws Exception {
 | 
				
			||||||
 | 
							MockHttpServletRequest request = new MockHttpServletRequest("GET",
 | 
				
			||||||
 | 
									"/cloudfoundryapplication/");
 | 
				
			||||||
 | 
							Map<String, CloudFoundryDiscoveryMvcEndpoint.Link> links = this.endpoint
 | 
				
			||||||
 | 
									.links(request).get("_links");
 | 
				
			||||||
 | 
							assertThat(links.get("self").getHref())
 | 
				
			||||||
 | 
									.isEqualTo("http://localhost/cloudfoundryapplication");
 | 
				
			||||||
 | 
							assertThat(links.get("a").getHref())
 | 
				
			||||||
 | 
									.isEqualTo("http://localhost/cloudfoundryapplication/a");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static class TestEndpoint extends AbstractEndpoint<Object> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							TestEndpoint(String id) {
 | 
				
			||||||
 | 
								super(id);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							@Override
 | 
				
			||||||
 | 
							public Object invoke() {
 | 
				
			||||||
 | 
								return null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static class TestMvcEndpoint extends EndpointMvcAdapter {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							TestMvcEndpoint(TestEndpoint delegate) {
 | 
				
			||||||
 | 
								super(delegate);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -17,12 +17,18 @@
 | 
				
			||||||
package org.springframework.boot.actuate.cloudfoundry;
 | 
					package org.springframework.boot.actuate.cloudfoundry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.Arrays;
 | 
					import java.util.Arrays;
 | 
				
			||||||
 | 
					import java.util.Collections;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import org.junit.Test;
 | 
					import org.junit.Test;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import org.springframework.boot.actuate.endpoint.AbstractEndpoint;
 | 
					import org.springframework.boot.actuate.endpoint.AbstractEndpoint;
 | 
				
			||||||
import org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter;
 | 
					import org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter;
 | 
				
			||||||
 | 
					import org.springframework.boot.actuate.endpoint.mvc.HalJsonMvcEndpoint;
 | 
				
			||||||
 | 
					import org.springframework.boot.actuate.endpoint.mvc.ManagementServletContext;
 | 
				
			||||||
 | 
					import org.springframework.boot.actuate.endpoint.mvc.NamedMvcEndpoint;
 | 
				
			||||||
 | 
					import org.springframework.context.support.StaticApplicationContext;
 | 
				
			||||||
import org.springframework.mock.web.MockHttpServletRequest;
 | 
					import org.springframework.mock.web.MockHttpServletRequest;
 | 
				
			||||||
 | 
					import org.springframework.web.method.HandlerMethod;
 | 
				
			||||||
import org.springframework.web.servlet.HandlerExecutionChain;
 | 
					import org.springframework.web.servlet.HandlerExecutionChain;
 | 
				
			||||||
import org.springframework.web.servlet.HandlerInterceptor;
 | 
					import org.springframework.web.servlet.HandlerInterceptor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -57,6 +63,28 @@ public class CloudFoundryEndpointHandlerMappingTests {
 | 
				
			||||||
		assertThat(handlerMapping.getPath(testMvcEndpoint)).isEqualTo("/a");
 | 
							assertThat(handlerMapping.getPath(testMvcEndpoint)).isEqualTo("/a");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Test
 | 
				
			||||||
 | 
						public void doesNotRegisterHalJsonMvcEndpoint() throws Exception {
 | 
				
			||||||
 | 
							CloudFoundryEndpointHandlerMapping handlerMapping = new CloudFoundryEndpointHandlerMapping(
 | 
				
			||||||
 | 
									Collections.<NamedMvcEndpoint>singleton(new TestHalJsonMvcEndpoint()));
 | 
				
			||||||
 | 
							assertThat(handlerMapping.getEndpoints()).hasSize(0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Test
 | 
				
			||||||
 | 
						public void registersCloudFoundryDiscoveryEndpoint() throws Exception {
 | 
				
			||||||
 | 
							StaticApplicationContext context = new StaticApplicationContext();
 | 
				
			||||||
 | 
							CloudFoundryEndpointHandlerMapping handlerMapping = new CloudFoundryEndpointHandlerMapping(
 | 
				
			||||||
 | 
									Collections.<NamedMvcEndpoint>emptyList());
 | 
				
			||||||
 | 
							handlerMapping.setPrefix("/test");
 | 
				
			||||||
 | 
							handlerMapping.setApplicationContext(context);
 | 
				
			||||||
 | 
							handlerMapping.afterPropertiesSet();
 | 
				
			||||||
 | 
							HandlerExecutionChain handler = handlerMapping
 | 
				
			||||||
 | 
									.getHandler(new MockHttpServletRequest("GET", "/test"));
 | 
				
			||||||
 | 
							HandlerMethod handlerMethod = (HandlerMethod) handler.getHandler();
 | 
				
			||||||
 | 
							assertThat(handlerMethod.getBean())
 | 
				
			||||||
 | 
									.isInstanceOf(CloudFoundryDiscoveryMvcEndpoint.class);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private static class TestEndpoint extends AbstractEndpoint<Object> {
 | 
						private static class TestEndpoint extends AbstractEndpoint<Object> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		TestEndpoint(String id) {
 | 
							TestEndpoint(String id) {
 | 
				
			||||||
| 
						 | 
					@ -78,4 +106,19 @@ public class CloudFoundryEndpointHandlerMappingTests {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static class TestHalJsonMvcEndpoint extends HalJsonMvcEndpoint {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							TestHalJsonMvcEndpoint() {
 | 
				
			||||||
 | 
								super(new ManagementServletContext() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									@Override
 | 
				
			||||||
 | 
									public String getContextPath() {
 | 
				
			||||||
 | 
										return "";
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue