Skip to content

Commit

Permalink
Merge branch '2.3.x' into 2.4.x
Browse files Browse the repository at this point in the history
Closes gh-25449
  • Loading branch information
wilkinsona committed Feb 26, 2021
2 parents 24b2bb9 + 8f72ca6 commit cb600f1
Show file tree
Hide file tree
Showing 14 changed files with 358 additions and 51 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors.
* Copyright 2012-2021 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.
Expand All @@ -24,9 +24,9 @@
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.model.Resource;

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.jersey.ManagementContextResourceConfigCustomizer;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType;
import org.springframework.boot.actuate.endpoint.ExposableEndpoint;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
Expand All @@ -43,7 +43,6 @@
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.autoconfigure.jersey.ResourceConfigCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;
Expand All @@ -67,14 +66,13 @@ class JerseyWebEndpointManagementContextConfiguration {

@Bean
JerseyWebEndpointsResourcesRegistrar jerseyWebEndpointsResourcesRegistrar(Environment environment,
ObjectProvider<ResourceConfig> resourceConfig, WebEndpointsSupplier webEndpointsSupplier,
ServletEndpointsSupplier servletEndpointsSupplier, EndpointMediaTypes endpointMediaTypes,
WebEndpointProperties webEndpointProperties) {
WebEndpointsSupplier webEndpointsSupplier, ServletEndpointsSupplier servletEndpointsSupplier,
EndpointMediaTypes endpointMediaTypes, WebEndpointProperties webEndpointProperties) {
String basePath = webEndpointProperties.getBasePath();
boolean shouldRegisterLinks = shouldRegisterLinksMapping(environment, basePath);
shouldRegisterLinksMapping(environment, basePath);
return new JerseyWebEndpointsResourcesRegistrar(resourceConfig.getIfAvailable(), webEndpointsSupplier,
servletEndpointsSupplier, endpointMediaTypes, basePath, shouldRegisterLinks);
return new JerseyWebEndpointsResourcesRegistrar(webEndpointsSupplier, servletEndpointsSupplier,
endpointMediaTypes, basePath, shouldRegisterLinks);
}

private boolean shouldRegisterLinksMapping(Environment environment, String basePath) {
Expand All @@ -83,12 +81,9 @@ private boolean shouldRegisterLinksMapping(Environment environment, String baseP
}

/**
* Register endpoints with the {@link ResourceConfig}. The
* {@link ResourceConfigCustomizer} cannot be used because we don't want to apply
* Register endpoints with the {@link ResourceConfig} for the management context.
*/
static class JerseyWebEndpointsResourcesRegistrar {

private final ResourceConfig resourceConfig;
static class JerseyWebEndpointsResourcesRegistrar implements ManagementContextResourceConfigCustomizer {

private final WebEndpointsSupplier webEndpointsSupplier;

Expand All @@ -100,33 +95,29 @@ static class JerseyWebEndpointsResourcesRegistrar {

private final boolean shouldRegisterLinks;

JerseyWebEndpointsResourcesRegistrar(ResourceConfig resourceConfig, WebEndpointsSupplier webEndpointsSupplier,
JerseyWebEndpointsResourcesRegistrar(WebEndpointsSupplier webEndpointsSupplier,
ServletEndpointsSupplier servletEndpointsSupplier, EndpointMediaTypes endpointMediaTypes,
String basePath, boolean shouldRegisterLinks) {
super();
this.resourceConfig = resourceConfig;
this.webEndpointsSupplier = webEndpointsSupplier;
this.servletEndpointsSupplier = servletEndpointsSupplier;
this.mediaTypes = endpointMediaTypes;
this.basePath = basePath;
this.shouldRegisterLinks = shouldRegisterLinks;
register();
}

private void register() {
// We can't easily use @ConditionalOnBean because @AutoConfigureBefore is
// not an option for management contexts. Instead we manually check if
// the resource config bean exists
if (this.resourceConfig == null) {
return;
}
@Override
public void customize(ResourceConfig config) {
register(config);
}

private void register(ResourceConfig config) {
Collection<ExposableWebEndpoint> webEndpoints = this.webEndpointsSupplier.getEndpoints();
Collection<ExposableServletEndpoint> servletEndpoints = this.servletEndpointsSupplier.getEndpoints();
EndpointLinksResolver linksResolver = getLinksResolver(webEndpoints, servletEndpoints);
EndpointMapping mapping = new EndpointMapping(this.basePath);
JerseyEndpointResourceFactory resourceFactory = new JerseyEndpointResourceFactory();
register(resourceFactory.createEndpointResources(mapping, webEndpoints, this.mediaTypes, linksResolver,
this.shouldRegisterLinks));
Collection<Resource> endpointResources = new JerseyEndpointResourceFactory().createEndpointResources(
mapping, webEndpoints, this.mediaTypes, linksResolver, this.shouldRegisterLinks);
register(endpointResources, config);
}

private EndpointLinksResolver getLinksResolver(Collection<ExposableWebEndpoint> webEndpoints,
Expand All @@ -137,8 +128,8 @@ private EndpointLinksResolver getLinksResolver(Collection<ExposableWebEndpoint>
return new EndpointLinksResolver(endpoints, this.basePath);
}

private void register(Collection<Resource> resources) {
this.resourceConfig.registerResources(new HashSet<>(resources));
private void register(Collection<Resource> resources, ResourceConfig config) {
config.registerResources(new HashSet<>(resources));
}

}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors.
* Copyright 2012-2021 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.
Expand All @@ -18,6 +18,7 @@

import org.glassfish.jersey.server.ResourceConfig;

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextType;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
Expand Down Expand Up @@ -47,4 +48,11 @@ public JerseyApplicationPath jerseyApplicationPath() {
return () -> "/";
}

@Bean
ResourceConfig resourceConfig(ObjectProvider<ManagementContextResourceConfigCustomizer> customizers) {
ResourceConfig resourceConfig = new ResourceConfig();
customizers.orderedStream().forEach((customizer) -> customizer.customize(resourceConfig));
return resourceConfig;
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors.
* Copyright 2012-2021 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.
Expand Down Expand Up @@ -39,9 +39,4 @@ ServletRegistrationBean<ServletContainer> jerseyServletRegistration(JerseyApplic
jerseyApplicationPath.getUrlMapping());
}

@Bean
ResourceConfig resourceConfig() {
return new ResourceConfig();
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors.
* Copyright 2012-2021 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.
Expand All @@ -18,17 +18,20 @@

import org.glassfish.jersey.server.ResourceConfig;

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextType;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.jersey.JerseyProperties;
import org.springframework.boot.autoconfigure.jersey.ResourceConfigCustomizer;
import org.springframework.boot.autoconfigure.web.servlet.DefaultJerseyApplicationPath;
import org.springframework.boot.autoconfigure.web.servlet.JerseyApplicationPath;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

/**
Expand All @@ -39,18 +42,36 @@
* @since 2.1.0
*/
@ManagementContextConfiguration(value = ManagementContextType.SAME, proxyBeanMethods = false)
@Import(JerseyManagementContextConfiguration.class)
@EnableConfigurationProperties(JerseyProperties.class)
@ConditionalOnMissingBean(ResourceConfig.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnClass(ResourceConfig.class)
@ConditionalOnMissingClass("org.springframework.web.servlet.DispatcherServlet")
public class JerseySameManagementContextConfiguration {

@Bean
@ConditionalOnMissingBean(JerseyApplicationPath.class)
public JerseyApplicationPath jerseyApplicationPath(JerseyProperties properties, ResourceConfig config) {
return new DefaultJerseyApplicationPath(properties.getApplicationPath(), config);
ResourceConfigCustomizer managementResourceConfigCustomizerAdapter(
ObjectProvider<ManagementContextResourceConfigCustomizer> customizers) {
return (config) -> customizers.orderedStream().forEach((customizer) -> customizer.customize(config));
}

@Configuration(proxyBeanMethods = false)
@Import(JerseyManagementContextConfiguration.class)
@ConditionalOnMissingBean(ResourceConfig.class)
class JerseyInfrastructureConfiguration {

@Bean
@ConditionalOnMissingBean(JerseyApplicationPath.class)
JerseyApplicationPath jerseyApplicationPath(JerseyProperties properties, ResourceConfig config) {
return new DefaultJerseyApplicationPath(properties.getApplicationPath(), config);
}

@Bean
ResourceConfig resourceConfig(ObjectProvider<ResourceConfigCustomizer> resourceConfigCustomizers) {
ResourceConfig resourceConfig = new ResourceConfig();
resourceConfigCustomizers.orderedStream().forEach((customizer) -> customizer.customize(resourceConfig));
return resourceConfig;
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright 2012-2021 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
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.boot.actuate.autoconfigure.web.jersey;

import org.glassfish.jersey.server.ResourceConfig;

/**
* Callback interface that can be implemented by beans wishing to customize Jersey's
* {@link ResourceConfig} in the management context before it is used.
*
* @author Andy Wilkinson
* @since 2.3.10
*/
public interface ManagementContextResourceConfigCustomizer {

/**
* Customize the resource config.
* @param config the {@link ResourceConfig} to customize
*/
void customize(ResourceConfig config);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Copyright 2012-2021 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
*
* https://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.jersey;

import java.util.Set;

import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.model.Resource;
import org.junit.jupiter.api.Test;

import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.jersey.JerseySameManagementContextConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration;
import org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener;
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.DispatcherServlet;

import static org.assertj.core.api.Assertions.assertThat;

/**
* Integration tests for web endpoints running on Jersey.
*
* @author Andy Wilkinson
*/
class JerseyWebEndpointIntegrationTests {

@Test
void whenJerseyIsConfiguredToUseAFilterThenResourceRegistrationSucceeds() {
new WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new)
.withConfiguration(AutoConfigurations.of(JerseySameManagementContextConfiguration.class,
JerseyAutoConfiguration.class, ServletWebServerFactoryAutoConfiguration.class,
EndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class,
JerseyWebEndpointManagementContextConfiguration.class))
.withUserConfiguration(ResourceConfigConfiguration.class)
.withClassLoader(new FilteredClassLoader(DispatcherServlet.class))
.withInitializer(new ConditionEvaluationReportLoggingListener(LogLevel.INFO))
.withPropertyValues("spring.jersey.type=filter", "server.port=0").run((context) -> {
assertThat(context).hasNotFailed();
Set<Resource> resources = context.getBean(ResourceConfig.class).getResources();
assertThat(resources).hasSize(1);
Resource resource = resources.iterator().next();
assertThat(resource.getPath()).isEqualTo("/actuator");
});
}

@Configuration(proxyBeanMethods = false)
static class ResourceConfigConfiguration {

@Bean
ResourceConfig resourceConfig() {
return new ResourceConfig();
}

}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2021 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.
Expand Down Expand Up @@ -27,8 +27,12 @@
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.testsupport.classpath.ClassPathExclusions;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

/**
* Tests for {@link JerseyChildManagementContextConfiguration}.
Expand Down Expand Up @@ -78,4 +82,25 @@ void resourceConfigCustomizerBeanIsNotRequired() {
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(ResourceConfig.class));
}

@Test
void resourceConfigIsCustomizedWithResourceConfigCustomizerBean() {
this.contextRunner.withUserConfiguration(CustomizerConfiguration.class).run((context) -> {
assertThat(context).hasSingleBean(ResourceConfig.class);
ResourceConfig config = context.getBean(ResourceConfig.class);
ManagementContextResourceConfigCustomizer customizer = context
.getBean(ManagementContextResourceConfigCustomizer.class);
verify(customizer).customize(config);
});
}

@Configuration(proxyBeanMethods = false)
static class CustomizerConfiguration {

@Bean
ManagementContextResourceConfigCustomizer resourceConfigCustomizer() {
return mock(ManagementContextResourceConfigCustomizer.class);
}

}

}

0 comments on commit cb600f1

Please sign in to comment.