Add @EndpointServlet and migrate Jolokia
Add first class support for Servlet based endpoints and rework the Jolokia endpoint to use it. Fixes gh-10264pull/11764/head
parent
f8cdc01474
commit
017efda6ec
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.endpoint.web;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;
|
||||
import org.springframework.boot.actuate.endpoint.web.ServletEndpointRegistrar;
|
||||
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* {@link ManagementContextConfiguration} for servlet endpoints.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnWebApplication(type = Type.SERVLET)
|
||||
public class ServletEndpointManagementContextConfiguration {
|
||||
|
||||
@Bean
|
||||
public ServletEndpointRegistrar servletEndpointRegistrar(
|
||||
WebEndpointProperties properties,
|
||||
ServletEndpointsSupplier servletEndpointsSupplier) {
|
||||
return new ServletEndpointRegistrar(properties.getBasePath(),
|
||||
servletEndpointsSupplier.getEndpoints());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.jolokia;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.jolokia.http.AgentServlet;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.web.EndpointServlet;
|
||||
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpoint;
|
||||
|
||||
/**
|
||||
* {@link Endpoint} to expose a Jolokia {@link AgentServlet}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@ServletEndpoint(id = "jolokia")
|
||||
public class JolokiaEndpoint implements Supplier<EndpointServlet> {
|
||||
|
||||
private Map<String, String> initParameters;
|
||||
|
||||
public JolokiaEndpoint(Map<String, String> initParameters) {
|
||||
this.initParameters = initParameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EndpointServlet get() {
|
||||
return new EndpointServlet(AgentServlet.class)
|
||||
.withInitParameters(this.initParameters);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.jolokia;
|
||||
|
||||
import org.jolokia.http.AgentServlet;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for the {@link JolokiaEndpoint}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnWebApplication(type = Type.SERVLET)
|
||||
@ConditionalOnClass(AgentServlet.class)
|
||||
@EnableConfigurationProperties(JolokiaProperties.class)
|
||||
public class JolokiaEndpointAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnEnabledEndpoint
|
||||
public JolokiaEndpoint jolokiaEndpoint(JolokiaProperties properties) {
|
||||
return new JolokiaEndpoint(properties.getConfig());
|
||||
}
|
||||
|
||||
}
|
@ -1,81 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.jolokia;
|
||||
|
||||
import org.jolokia.http.AgentServlet;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.web.servlet.ManagementServletContext;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.web.servlet.ServletRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.web.servlet.mvc.ServletWrappingController;
|
||||
|
||||
/**
|
||||
* {@link ManagementContextConfiguration} for embedding Jolokia, a JMX-HTTP bridge giving
|
||||
* an alternative to JSR-160 connectors.
|
||||
* <p>
|
||||
* This configuration will get automatically enabled as soon as the Jolokia
|
||||
* {@link AgentServlet} is on the classpath. To disable it set
|
||||
* {@code management.jolokia.enabled=false}.
|
||||
* <p>
|
||||
* Additional configuration parameters for Jolokia can be provided by specifying
|
||||
* {@code management.jolokia.config.*} properties. See the
|
||||
* <a href="http://jolokia.org">http://jolokia.org</a> web site for more information on
|
||||
* supported configuration parameters.
|
||||
*
|
||||
* @author Christian Dupuis
|
||||
* @author Dave Syer
|
||||
* @author Andy Wilkinson
|
||||
* @author Madhura Bhave
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@ManagementContextConfiguration
|
||||
@ConditionalOnWebApplication(type = Type.SERVLET)
|
||||
@ConditionalOnClass({ AgentServlet.class, ServletWrappingController.class })
|
||||
@ConditionalOnProperty(value = "management.jolokia.enabled", havingValue = "true")
|
||||
@EnableConfigurationProperties(JolokiaProperties.class)
|
||||
public class JolokiaManagementContextConfiguration {
|
||||
|
||||
private final ManagementServletContext managementServletContext;
|
||||
|
||||
private final JolokiaProperties properties;
|
||||
|
||||
public JolokiaManagementContextConfiguration(
|
||||
ManagementServletContext managementServletContext,
|
||||
JolokiaProperties properties) {
|
||||
this.managementServletContext = managementServletContext;
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ServletRegistrationBean<AgentServlet> jolokiaServlet() {
|
||||
String path = this.managementServletContext.getServletPath()
|
||||
+ this.properties.getPath();
|
||||
String urlMapping = (path.endsWith("/") ? path + "*" : path + "/*");
|
||||
ServletRegistrationBean<AgentServlet> registration = new ServletRegistrationBean<>(
|
||||
new AgentServlet(), urlMapping);
|
||||
registration.setInitParameters(this.properties.getConfig());
|
||||
return registration;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.endpoint.web;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.web.ServletEndpointRegistrar;
|
||||
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link ServletEndpointManagementContextConfiguration}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class ServletEndpointManagementContextConfigurationTests {
|
||||
|
||||
private WebApplicationContextRunner runner = new WebApplicationContextRunner()
|
||||
.withUserConfiguration(TestConfig.class);
|
||||
|
||||
@Test
|
||||
public void contextShouldContainServletEndpointRegistrar() {
|
||||
this.runner.run((context) -> assertThat(context)
|
||||
.hasSingleBean(ServletEndpointRegistrar.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void contextWhenNoServletBasedShouldNotContainServletEndpointRegistrar() {
|
||||
new ApplicationContextRunner().withUserConfiguration(TestConfig.class)
|
||||
.run((context) -> assertThat(context)
|
||||
.doesNotHaveBean(ServletEndpointRegistrar.class));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import(ServletEndpointManagementContextConfiguration.class)
|
||||
@EnableConfigurationProperties(WebEndpointProperties.class)
|
||||
static class TestConfig {
|
||||
|
||||
@Bean
|
||||
public ServletEndpointsSupplier servletEndpointsSupplier() {
|
||||
return () -> Collections.emptyList();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.jolokia;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.jolokia.http.AgentServlet;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.web.ServletEndpointManagementContextConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration;
|
||||
import org.springframework.boot.actuate.endpoint.web.ExposableServletEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.web.PathMapper;
|
||||
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointDiscoverer;
|
||||
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link JolokiaEndpointAutoConfiguration}.
|
||||
*
|
||||
* @author Christian Dupuis
|
||||
* @author Andy Wilkinson
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public class JolokiaEndpointAutoConfigurationTests {
|
||||
|
||||
private final WebApplicationContextRunner runner = new WebApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(
|
||||
ManagementContextAutoConfiguration.class,
|
||||
ServletManagementContextAutoConfiguration.class,
|
||||
ServletEndpointManagementContextConfiguration.class,
|
||||
JolokiaEndpointAutoConfiguration.class, TestConfiguration.class));
|
||||
|
||||
@Test
|
||||
public void jolokiaServletShouldBeEnabledByDefault() {
|
||||
this.runner.run((context) -> {
|
||||
ExposableServletEndpoint endpoint = getEndpoint(context);
|
||||
assertThat(endpoint.getRootPath()).isEqualTo("jolokia");
|
||||
Object servlet = ReflectionTestUtils.getField(endpoint.getEndpointServlet(),
|
||||
"servlet");
|
||||
assertThat(servlet).isInstanceOf(AgentServlet.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jolokiaServletWhenDisabledShouldNotBeDiscovered() {
|
||||
this.runner.withPropertyValues("management.endpoint.jolokia.enabled=false")
|
||||
.run((context) -> {
|
||||
Collection<ExposableServletEndpoint> endpoints = context
|
||||
.getBean(ServletEndpointsSupplier.class).getEndpoints();
|
||||
assertThat(endpoints).isEmpty();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jolokiaServletWhenHasCustomConfigShouldApplyInitParams() {
|
||||
this.runner.withPropertyValues("management.endpoint.jolokia.config.debug=true")
|
||||
.run((context) -> {
|
||||
ExposableServletEndpoint endpoint = getEndpoint(context);
|
||||
assertThat(endpoint.getEndpointServlet()).extracting("initParameters")
|
||||
.containsOnly(Collections.singletonMap("debug", "true"));
|
||||
});
|
||||
}
|
||||
|
||||
private ExposableServletEndpoint getEndpoint(
|
||||
AssertableWebApplicationContext context) {
|
||||
Collection<ExposableServletEndpoint> endpoints = context
|
||||
.getBean(ServletEndpointsSupplier.class).getEndpoints();
|
||||
return endpoints.iterator().next();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class TestConfiguration {
|
||||
|
||||
@Bean
|
||||
public ServletEndpointDiscoverer servletEndpointDiscoverer(
|
||||
ApplicationContext applicationContext) {
|
||||
return new ServletEndpointDiscoverer(applicationContext,
|
||||
PathMapper.useEndpointId(), Collections.emptyList());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.jolokia;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
|
||||
import org.springframework.boot.test.context.runner.ContextConsumer;
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
import org.springframework.boot.web.servlet.ServletRegistrationBean;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.entry;
|
||||
|
||||
/**
|
||||
* Tests for {@link JolokiaManagementContextConfiguration}.
|
||||
*
|
||||
* @author Christian Dupuis
|
||||
* @author Andy Wilkinson
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public class JolokiaManagementContextConfigurationTests {
|
||||
|
||||
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
|
||||
.withConfiguration(
|
||||
AutoConfigurations.of(ManagementContextAutoConfiguration.class,
|
||||
ServletManagementContextAutoConfiguration.class,
|
||||
JolokiaManagementContextConfiguration.class));
|
||||
|
||||
@Test
|
||||
public void jolokiaCanBeEnabled() {
|
||||
this.contextRunner.withPropertyValues("management.jolokia.enabled=true")
|
||||
.run((context) -> {
|
||||
context.getBean(ServletRegistrationBean.class);
|
||||
assertThat(context).hasSingleBean(ServletRegistrationBean.class);
|
||||
ServletRegistrationBean<?> registrationBean = context
|
||||
.getBean(ServletRegistrationBean.class);
|
||||
assertThat(registrationBean.getUrlMappings())
|
||||
.contains("/actuator/jolokia/*");
|
||||
assertThat(registrationBean.getInitParameters()).isEmpty();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jolokiaIsDisabledByDefault() {
|
||||
this.contextRunner.run((context) -> assertThat(context)
|
||||
.doesNotHaveBean(ServletRegistrationBean.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customPath() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("management.jolokia.enabled=true",
|
||||
"management.jolokia.path=/lokia")
|
||||
.run(isDefinedOnPath("/actuator/lokia/*"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customManagementPath() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("management.jolokia.enabled=true",
|
||||
"management.endpoints.web.base-path=/admin")
|
||||
.run(isDefinedOnPath("/admin/jolokia/*"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customInitParameters() {
|
||||
this.contextRunner.withPropertyValues("management.jolokia.enabled=true",
|
||||
"management.jolokia.config.debug=true").run((context) -> {
|
||||
assertThat(context).hasSingleBean(ServletRegistrationBean.class);
|
||||
ServletRegistrationBean<?> registrationBean = context
|
||||
.getBean(ServletRegistrationBean.class);
|
||||
assertThat(registrationBean.getInitParameters())
|
||||
.containsOnly(entry("debug", "true"));
|
||||
});
|
||||
}
|
||||
|
||||
private ContextConsumer<AssertableWebApplicationContext> isDefinedOnPath(
|
||||
String path) {
|
||||
return (context) -> {
|
||||
assertThat(context).hasSingleBean(ServletRegistrationBean.class);
|
||||
ServletRegistrationBean<?> registrationBean = context
|
||||
.getBean(ServletRegistrationBean.class);
|
||||
assertThat(registrationBean.getUrlMappings()).containsExactly(path);
|
||||
};
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2012-2018 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.web;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.Servlet;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Contains details of a servlet that is exposed as an actuator endpoint.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public final class EndpointServlet {
|
||||
|
||||
private final Servlet servlet;
|
||||
|
||||
private final Map<String, String> initParameters;
|
||||
|
||||
public EndpointServlet(Class<? extends Servlet> servlet) {
|
||||
Assert.notNull(servlet, "Servlet must not be null");
|
||||
this.servlet = BeanUtils.instantiateClass(servlet);
|
||||
this.initParameters = Collections.emptyMap();
|
||||
}
|
||||
|
||||
public EndpointServlet(Servlet servlet) {
|
||||
Assert.notNull(servlet, "Servlet must not be null");
|
||||
this.servlet = servlet;
|
||||
this.initParameters = Collections.emptyMap();
|
||||
}
|
||||
|
||||
private EndpointServlet(Servlet servlet, Map<String, String> initParameters) {
|
||||
this.servlet = servlet;
|
||||
this.initParameters = Collections.unmodifiableMap(initParameters);
|
||||
}
|
||||
|
||||
public EndpointServlet withInitParameter(String name, String value) {
|
||||
Assert.hasText(name, "Name must not be empty");
|
||||
return withInitParameters(Collections.singletonMap(name, value));
|
||||
}
|
||||
|
||||
public EndpointServlet withInitParameters(Map<String, String> initParameters) {
|
||||
Assert.notNull(initParameters, "InitParameters must not be null");
|
||||
boolean hasEmptyKey = initParameters.values().stream()
|
||||
.anyMatch((key) -> !StringUtils.hasText(key));
|
||||
Assert.isTrue(!hasEmptyKey, "InitParameters must not contain empty keys");
|
||||
Map<String, String> mergedInitParameters = new LinkedHashMap<>(
|
||||
this.initParameters);
|
||||
mergedInitParameters.putAll(initParameters);
|
||||
return new EndpointServlet(this.servlet, mergedInitParameters);
|
||||
}
|
||||
|
||||
Servlet getServlet() {
|
||||
return this.servlet;
|
||||
}
|
||||
|
||||
Map<String, String> getInitParameters() {
|
||||
return this.initParameters;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2012-2018 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.web;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.ExposableEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.Operation;
|
||||
|
||||
/**
|
||||
* Information describing an endpoint that can be exposed by registering a servlet.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public interface ExposableServletEndpoint
|
||||
extends ExposableEndpoint<Operation>, PathMappedEndpoint {
|
||||
|
||||
/**
|
||||
* Return details of the servlet that should registered.
|
||||
* @return the endpoint servlet
|
||||
*/
|
||||
EndpointServlet getEndpointServlet();
|
||||
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2012-2018 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.web;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRegistration.Dynamic;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.boot.web.servlet.ServletContextInitializer;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link ServletContextInitializer} to register {@link ExposableServletEndpoint} servlet
|
||||
* endpoints.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class ServletEndpointRegistrar implements ServletContextInitializer {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(ServletEndpointRegistrar.class);
|
||||
|
||||
private final String basePath;
|
||||
|
||||
private final Collection<ExposableServletEndpoint> servletEndpoints;
|
||||
|
||||
public ServletEndpointRegistrar(String basePath,
|
||||
Collection<ExposableServletEndpoint> servletEndpoints) {
|
||||
Assert.notNull(servletEndpoints, "ServletEndpoints must not be null");
|
||||
this.basePath = (basePath == null ? "" : basePath);
|
||||
this.servletEndpoints = servletEndpoints;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartup(ServletContext servletContext) throws ServletException {
|
||||
this.servletEndpoints.forEach((servletEndpoint) -> {
|
||||
register(servletContext, servletEndpoint);
|
||||
});
|
||||
}
|
||||
|
||||
private void register(ServletContext servletContext,
|
||||
ExposableServletEndpoint endpoint) {
|
||||
String name = endpoint.getId() + "-actuator-endpoint";
|
||||
String path = this.basePath + "/" + endpoint.getRootPath();
|
||||
String urlMapping = (path.endsWith("/") ? path + "*" : path + "/*");
|
||||
EndpointServlet endpointServlet = endpoint.getEndpointServlet();
|
||||
Dynamic registration = servletContext.addServlet(name,
|
||||
endpointServlet.getServlet());
|
||||
registration.addMapping(urlMapping);
|
||||
registration.setInitParameters(endpointServlet.getInitParameters());
|
||||
logger.info("Registered '" + path + "' to " + name);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2012-2018 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.web.annotation;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.Operation;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.AbstractDiscoveredEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer;
|
||||
import org.springframework.boot.actuate.endpoint.web.EndpointServlet;
|
||||
import org.springframework.boot.actuate.endpoint.web.ExposableServletEndpoint;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A discovered {@link ExposableServletEndpoint controller endpoint}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class DiscoveredServletEndpoint extends AbstractDiscoveredEndpoint<Operation>
|
||||
implements ExposableServletEndpoint {
|
||||
|
||||
private final String rootPath;
|
||||
|
||||
private final EndpointServlet endpointServlet;
|
||||
|
||||
DiscoveredServletEndpoint(EndpointDiscoverer<?, ?> discoverer, Object endpointBean,
|
||||
String id, String rootPath, boolean enabledByDefault) {
|
||||
super(discoverer, endpointBean, id, enabledByDefault, Collections.emptyList());
|
||||
String beanType = endpointBean.getClass().getName();
|
||||
Assert.state(endpointBean instanceof Supplier,
|
||||
() -> "ServletEndpoint bean " + beanType + " must be a supplier");
|
||||
Object supplied = ((Supplier<?>) endpointBean).get();
|
||||
Assert.state(supplied != null,
|
||||
"ServletEndpoint bean " + beanType + " must not supply null");
|
||||
Assert.state(supplied instanceof EndpointServlet, () -> "ServletEndpoint bean "
|
||||
+ beanType + " must supply an EndpointServlet");
|
||||
this.endpointServlet = (EndpointServlet) supplied;
|
||||
this.rootPath = rootPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRootPath() {
|
||||
return this.rootPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EndpointServlet getEndpointServlet() {
|
||||
return this.endpointServlet;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2012-2018 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.web.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.FilteredEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.web.EndpointServlet;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
|
||||
/**
|
||||
* Identifies a type as being an endpoint that supplies a servlet to expose.
|
||||
* Implementations must also implement {@link Supplier Supplier<EndpointServlet>}
|
||||
* and return a valid {@link EndpointServlet}.
|
||||
* <p>
|
||||
* This annotation can be used when existing servlets need be be exposed as actuator
|
||||
* endpoints, but it is at the expense of portability. Most users should prefer the
|
||||
* {@link Endpoint @Endpoint} or {@link WebEndpoint @WebEndpoint} annotations whenever
|
||||
* possible.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Endpoint
|
||||
@FilteredEndpoint(ServletEndpointFilter.class)
|
||||
public @interface ServletEndpoint {
|
||||
|
||||
/**
|
||||
* The id of the endpoint.
|
||||
* @return the id
|
||||
*/
|
||||
@AliasFor(annotation = Endpoint.class)
|
||||
String id();
|
||||
|
||||
/**
|
||||
* If the endpoint should be enabled or disabled by default.
|
||||
* @return {@code true} if the endpoint is enabled by default
|
||||
*/
|
||||
@AliasFor(annotation = Endpoint.class)
|
||||
boolean enableByDefault() default true;
|
||||
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2012-2018 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.web.annotation;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.EndpointFilter;
|
||||
import org.springframework.boot.actuate.endpoint.Operation;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.DiscoveredOperationMethod;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer;
|
||||
import org.springframework.boot.actuate.endpoint.invoke.OperationInvoker;
|
||||
import org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper;
|
||||
import org.springframework.boot.actuate.endpoint.web.ExposableServletEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.web.PathMapper;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link EndpointDiscoverer} for {@link ExposableServletEndpoint servlet endpoints}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class ServletEndpointDiscoverer
|
||||
extends EndpointDiscoverer<ExposableServletEndpoint, Operation>
|
||||
implements ServletEndpointsSupplier {
|
||||
|
||||
private final PathMapper endpointPathMapper;
|
||||
|
||||
/**
|
||||
* Create a new {@link ServletEndpointFilter} instance.
|
||||
* @param applicationContext the source application context
|
||||
* @param endpointPathMapper the endpoint path mapper
|
||||
* @param filters filters to apply
|
||||
*/
|
||||
public ServletEndpointDiscoverer(ApplicationContext applicationContext,
|
||||
PathMapper endpointPathMapper,
|
||||
Collection<EndpointFilter<ExposableServletEndpoint>> filters) {
|
||||
super(applicationContext, ParameterValueMapper.NONE, Collections.emptyList(),
|
||||
filters);
|
||||
Assert.notNull(endpointPathMapper, "EndpointPathMapper must not be null");
|
||||
this.endpointPathMapper = endpointPathMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isEndpointExposed(Object endpointBean) {
|
||||
Class<?> type = endpointBean.getClass();
|
||||
return AnnotatedElementUtils.isAnnotated(type, ServletEndpoint.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExposableServletEndpoint createEndpoint(Object endpointBean, String id,
|
||||
boolean enabledByDefault, Collection<Operation> operations) {
|
||||
String rootPath = this.endpointPathMapper.getRootPath(id);
|
||||
return new DiscoveredServletEndpoint(this, endpointBean, id, rootPath,
|
||||
enabledByDefault);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Operation createOperation(String endpointId,
|
||||
DiscoveredOperationMethod operationMethod, OperationInvoker invoker) {
|
||||
throw new IllegalStateException("ServletEndpoints must not declare operations");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected OperationKey createOperationKey(Operation operation) {
|
||||
throw new IllegalStateException("ServletEndpoints must not declare operations");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2012-2018 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.web.annotation;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.EndpointFilter;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.DiscovererEndpointFilter;
|
||||
|
||||
/**
|
||||
* {@link EndpointFilter} for endpoints discovered by {@link ServletEndpointDiscoverer}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class ServletEndpointFilter extends DiscovererEndpointFilter {
|
||||
|
||||
ServletEndpointFilter() {
|
||||
super(ServletEndpointDiscoverer.class);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2012-2018 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.web.annotation;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.EndpointsSupplier;
|
||||
import org.springframework.boot.actuate.endpoint.web.ExposableServletEndpoint;
|
||||
|
||||
/**
|
||||
* {@link EndpointsSupplier} for {@link ExposableServletEndpoint servlet endpoints}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ServletEndpointsSupplier
|
||||
extends EndpointsSupplier<ExposableServletEndpoint> {
|
||||
|
||||
}
|
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright 2012-2018 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.web;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.GenericServlet;
|
||||
import javax.servlet.Servlet;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.entry;
|
||||
|
||||
/**
|
||||
* Tests for {@link EndpointServlet}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class EndpointServletTests {
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void createWhenServletClassIsNullShouldThrowException() {
|
||||
this.thrown.expect(IllegalArgumentException.class);
|
||||
this.thrown.expectMessage("Servlet must not be null");
|
||||
new EndpointServlet((Class<Servlet>) null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createWhenServletIsNullShouldThrowException() {
|
||||
this.thrown.expect(IllegalArgumentException.class);
|
||||
this.thrown.expectMessage("Servlet must not be null");
|
||||
new EndpointServlet((Servlet) null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createWithServletClassShouldCreateServletInstance() {
|
||||
EndpointServlet endpointServlet = new EndpointServlet(TestServlet.class);
|
||||
assertThat(endpointServlet.getServlet()).isInstanceOf(TestServlet.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getServletShouldGetServlet() {
|
||||
TestServlet servlet = new TestServlet();
|
||||
EndpointServlet endpointServlet = new EndpointServlet(servlet);
|
||||
assertThat(endpointServlet.getServlet()).isEqualTo(servlet);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withInitParameterShouldReturnNewInstance() {
|
||||
EndpointServlet endpointServlet = new EndpointServlet(TestServlet.class);
|
||||
assertThat(endpointServlet.withInitParameter("spring", "boot"))
|
||||
.isNotSameAs(endpointServlet);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withInitParameterWhenHasExistingShouldMergeParameters() {
|
||||
EndpointServlet endpointServlet = new EndpointServlet(TestServlet.class)
|
||||
.withInitParameter("a", "b").withInitParameter("c", "d");
|
||||
assertThat(endpointServlet.withInitParameter("a", "b1")
|
||||
.withInitParameter("e", "f").getInitParameters()).containsExactly(
|
||||
entry("a", "b1"), entry("c", "d"), entry("e", "f"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withInitParametersShouldCreateNewInstance() {
|
||||
EndpointServlet endpointServlet = new EndpointServlet(TestServlet.class);
|
||||
assertThat(endpointServlet
|
||||
.withInitParameters(Collections.singletonMap("spring", "boot")))
|
||||
.isNotSameAs(endpointServlet);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withInitParametersWhenHasExistingShouldMergeParameters() {
|
||||
EndpointServlet endpointServlet = new EndpointServlet(TestServlet.class)
|
||||
.withInitParameter("a", "b").withInitParameter("c", "d");
|
||||
Map<String, String> extra = new LinkedHashMap<>();
|
||||
extra.put("a", "b1");
|
||||
extra.put("e", "f");
|
||||
assertThat(endpointServlet.withInitParameters(extra).getInitParameters())
|
||||
.containsExactly(entry("a", "b1"), entry("c", "d"), entry("e", "f"));
|
||||
|
||||
}
|
||||
|
||||
private static class TestServlet extends GenericServlet {
|
||||
|
||||
@Override
|
||||
public void service(ServletRequest req, ServletResponse res)
|
||||
throws ServletException, IOException {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright 2012-2018 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.web;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
|
||||
import javax.servlet.GenericServlet;
|
||||
import javax.servlet.Servlet;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRegistration.Dynamic;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* Tests for {@link ServletEndpointRegistrar}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class ServletEndpointRegistrarTests {
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Mock
|
||||
private ServletContext servletContext;
|
||||
|
||||
@Mock
|
||||
private Dynamic dynamic;
|
||||
|
||||
@Captor
|
||||
private ArgumentCaptor<Servlet> servlet;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
given(this.servletContext.addServlet(any(String.class), any(Servlet.class)))
|
||||
.willReturn(this.dynamic);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createWhenServletEndpointsIsNullShouldThrowException() {
|
||||
this.thrown.expect(IllegalArgumentException.class);
|
||||
this.thrown.expectMessage("ServletEndpoints must not be null");
|
||||
new ServletEndpointRegistrar(null, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStartupShouldRegisterServlets() throws Exception {
|
||||
ExposableServletEndpoint endpoint = mockEndpoint(
|
||||
new EndpointServlet(TestServlet.class));
|
||||
ServletEndpointRegistrar registrar = new ServletEndpointRegistrar(null,
|
||||
Collections.singleton(endpoint));
|
||||
registrar.onStartup(this.servletContext);
|
||||
verify(this.servletContext).addServlet(eq("test-actuator-endpoint"),
|
||||
this.servlet.capture());
|
||||
assertThat(this.servlet.getValue()).isInstanceOf(TestServlet.class);
|
||||
verify(this.dynamic).addMapping("/test/*");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStartupWhenHasBasePathShouldIncludeBasePath() throws Exception {
|
||||
ExposableServletEndpoint endpoint = mockEndpoint(
|
||||
new EndpointServlet(TestServlet.class));
|
||||
ServletEndpointRegistrar registrar = new ServletEndpointRegistrar("/actuator",
|
||||
Collections.singleton(endpoint));
|
||||
registrar.onStartup(this.servletContext);
|
||||
verify(this.servletContext).addServlet(eq("test-actuator-endpoint"),
|
||||
this.servlet.capture());
|
||||
assertThat(this.servlet.getValue()).isInstanceOf(TestServlet.class);
|
||||
verify(this.dynamic).addMapping("/actuator/test/*");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStartupWhenHasInitParametersShouldRegisterInitParameters()
|
||||
throws Exception {
|
||||
ExposableServletEndpoint endpoint = mockEndpoint(
|
||||
new EndpointServlet(TestServlet.class).withInitParameter("a", "b"));
|
||||
ServletEndpointRegistrar registrar = new ServletEndpointRegistrar("/actuator",
|
||||
Collections.singleton(endpoint));
|
||||
registrar.onStartup(this.servletContext);
|
||||
verify(this.dynamic).setInitParameters(Collections.singletonMap("a", "b"));
|
||||
}
|
||||
|
||||
private ExposableServletEndpoint mockEndpoint(EndpointServlet endpointServlet) {
|
||||
ExposableServletEndpoint endpoint = mock(ExposableServletEndpoint.class);
|
||||
given(endpoint.getId()).willReturn("test");
|
||||
given(endpoint.getEndpointServlet()).willReturn(endpointServlet);
|
||||
given(endpoint.getRootPath()).willReturn("test");
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
public static class TestServlet extends GenericServlet {
|
||||
|
||||
@Override
|
||||
public void service(ServletRequest req, ServletResponse res)
|
||||
throws ServletException, IOException {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,212 @@
|
||||
/*
|
||||
* Copyright 2012-2018 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.web.annotation;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.servlet.GenericServlet;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.ExposableEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.DiscoveredEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
||||
import org.springframework.boot.actuate.endpoint.web.EndpointServlet;
|
||||
import org.springframework.boot.actuate.endpoint.web.ExposableServletEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.web.PathMapper;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link ServletEndpointDiscoverer}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class ServletEndpointDiscovererTests {
|
||||
|
||||
@Rule
|
||||
public final ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void getEndpointsWhenNoEndpointBeansShouldReturnEmptyCollection() {
|
||||
load(EmptyConfiguration.class,
|
||||
(discoverer) -> assertThat(discoverer.getEndpoints()).isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getEndpointsShouldIncludeServletEndpoints() {
|
||||
load(TestServletEndpoint.class, (discoverer) -> {
|
||||
Collection<ExposableServletEndpoint> endpoints = discoverer.getEndpoints();
|
||||
assertThat(endpoints).hasSize(1);
|
||||
ExposableServletEndpoint endpoint = endpoints.iterator().next();
|
||||
assertThat(endpoint.getId()).isEqualTo("testservlet");
|
||||
assertThat(endpoint.getEndpointServlet()).isNotNull();
|
||||
assertThat(endpoint).isInstanceOf(DiscoveredEndpoint.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getEndpointsShouldNotDiscoverRegularEndpoints() {
|
||||
load(WithRegularEndpointConfiguration.class, (discoverer) -> {
|
||||
Collection<ExposableServletEndpoint> endpoints = discoverer.getEndpoints();
|
||||
List<String> ids = endpoints.stream().map(ExposableEndpoint::getId)
|
||||
.collect(Collectors.toList());
|
||||
assertThat(ids).containsOnly("testservlet");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getEndpointWhenEndpointHasOperationsShouldThrowException() {
|
||||
load(TestServletEndpointWithOperation.class, (discoverer) -> {
|
||||
this.thrown.expect(IllegalStateException.class);
|
||||
this.thrown.expectMessage("ServletEndpoints must not declare operations");
|
||||
discoverer.getEndpoints();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getEndpointWhenEndpointNotASupplierShouldThrowException() {
|
||||
load(TestServletEndpointNotASupplier.class, (discoverer) -> {
|
||||
this.thrown.expect(IllegalStateException.class);
|
||||
this.thrown.expectMessage("must be a supplier");
|
||||
discoverer.getEndpoints();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getEndpointWhenEndpointSuppliesWrongTypeShouldThrowException() {
|
||||
load(TestServletEndpointSupplierOfWrongType.class, (discoverer) -> {
|
||||
this.thrown.expect(IllegalStateException.class);
|
||||
this.thrown.expectMessage("must supply an EndpointServlet");
|
||||
discoverer.getEndpoints();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getEndpointWhenEndpoinSuppliesNullShouldThrowException() {
|
||||
load(TestServletEndpointSupplierOfNull.class, (discoverer) -> {
|
||||
this.thrown.expect(IllegalStateException.class);
|
||||
this.thrown.expectMessage("must not supply null");
|
||||
discoverer.getEndpoints();
|
||||
});
|
||||
}
|
||||
|
||||
private void load(Class<?> configuration,
|
||||
Consumer<ServletEndpointDiscoverer> consumer) {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
|
||||
configuration);
|
||||
try {
|
||||
ServletEndpointDiscoverer discoverer = new ServletEndpointDiscoverer(context,
|
||||
PathMapper.useEndpointId(), Collections.emptyList());
|
||||
consumer.accept(discoverer);
|
||||
}
|
||||
finally {
|
||||
context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class EmptyConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import({ TestEndpoint.class, TestServletEndpoint.class })
|
||||
static class WithRegularEndpointConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@ServletEndpoint(id = "testservlet")
|
||||
static class TestServletEndpoint implements Supplier<EndpointServlet> {
|
||||
|
||||
@Override
|
||||
public EndpointServlet get() {
|
||||
return new EndpointServlet(TestServlet.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Endpoint(id = "test")
|
||||
static class TestEndpoint {
|
||||
|
||||
}
|
||||
|
||||
@ServletEndpoint(id = "testservlet")
|
||||
static class TestServletEndpointWithOperation implements Supplier<EndpointServlet> {
|
||||
|
||||
@Override
|
||||
public EndpointServlet get() {
|
||||
return new EndpointServlet(TestServlet.class);
|
||||
}
|
||||
|
||||
@ReadOperation
|
||||
public String read() {
|
||||
return "error";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class TestServlet extends GenericServlet {
|
||||
|
||||
@Override
|
||||
public void service(ServletRequest req, ServletResponse res)
|
||||
throws ServletException, IOException {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ServletEndpoint(id = "testservlet")
|
||||
static class TestServletEndpointNotASupplier {
|
||||
|
||||
}
|
||||
|
||||
@ServletEndpoint(id = "testservlet")
|
||||
static class TestServletEndpointSupplierOfWrongType implements Supplier<String> {
|
||||
|
||||
@Override
|
||||
public String get() {
|
||||
return "error";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ServletEndpoint(id = "testservlet")
|
||||
static class TestServletEndpointSupplierOfNull implements Supplier<EndpointServlet> {
|
||||
|
||||
@Override
|
||||
public EndpointServlet get() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue