Enable resource chain if webjars locator is present

Webjars locator is a good hint that the resource chain should be
enabled. The sole presence of the library now enables the resource chain
unless the configuration states otherwise.

Closes gh-4403
This commit is contained in:
Stephane Nicoll 2015-11-30 15:00:44 +01:00
parent 7842f50e30
commit af5d765a08
5 changed files with 144 additions and 37 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2015 the original author or authors.
* 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.
@ -26,7 +26,8 @@ import org.springframework.context.annotation.Conditional;
/**
* {@link Conditional} that checks whether or not the Spring resource handling chain is
* enabled. Matches if {@link ResourceProperties.Chain#getEnabled()} is {@code true}.
* enabled. Matches if {@link ResourceProperties.Chain#getEnabled()} is {@code true} or
* if {@code webjars-locator} is on the classpath.
*
* @author Stephane Nicoll
* @since 1.3.0

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2015 the original author or authors.
* 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.
@ -24,6 +24,7 @@ import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.util.ClassUtils;
/**
* {@link Condition} that checks whether or not the Spring resource handling chain is
@ -33,6 +34,8 @@ import org.springframework.core.type.AnnotatedTypeMetadata;
*/
class OnEnabledResourceChainCondition extends SpringBootCondition {
public static final String WEBJAR_ASSERT_LOCATOR = "org.webjars.WebJarAssetLocator";
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context,
AnnotatedTypeMetadata metadata) {
@ -42,6 +45,13 @@ class OnEnabledResourceChainCondition extends SpringBootCondition {
RelaxedDataBinder binder = new RelaxedDataBinder(properties, "spring.resources");
binder.bind(new PropertySourcesPropertyValues(environment.getPropertySources()));
Boolean match = properties.getChain().getEnabled();
if (match == null) {
boolean webJarsLocatorPresent = ClassUtils.isPresent(
WEBJAR_ASSERT_LOCATOR, getClass().getClassLoader());
return new ConditionOutcome(webJarsLocatorPresent,
"Webjars locator (" + WEBJAR_ASSERT_LOCATOR + ") is "
+ (webJarsLocatorPresent ? "present" : "absent"));
}
return new ConditionOutcome(match,
"Resource chain is " + (match ? "enabled" : "disabled"));
}

View File

@ -172,10 +172,15 @@ public class ResourceProperties implements ResourceLoaderAware {
@NestedConfigurationProperty
private final Strategy strategy = new Strategy();
/**
* Return whether the resource chain is enabled. Return {@code null} if no
* specific settings are present.
*/
public Boolean getEnabled() {
return Boolean.TRUE.equals(this.enabled)
|| getStrategy().getFixed().isEnabled()
// Check if at least one of the available strategy has been enabled
Boolean strategyEnabled = getStrategy().getFixed().isEnabled()
|| getStrategy().getContent().isEnabled();
return (strategyEnabled ? Boolean.TRUE : this.enabled);
}
public void setEnabled(boolean enabled) {

View File

@ -148,6 +148,9 @@ public class WebMvcAutoConfiguration {
@Autowired
private HttpMessageConverters messageConverters;
@Autowired(required = false)
ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer;
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.addAll(this.messageConverters.getConverters());
@ -255,51 +258,24 @@ public class WebMvcAutoConfiguration {
}
Integer cachePeriod = this.resourceProperties.getCachePeriod();
if (!registry.hasMappingForPattern("/webjars/**")) {
registerResourceChain(registry.addResourceHandler("/webjars/**")
customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/")
.setCachePeriod(cachePeriod));
}
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
if (!registry.hasMappingForPattern(staticPathPattern)) {
registerResourceChain(registry.addResourceHandler(staticPathPattern)
customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern)
.addResourceLocations(
this.resourceProperties.getStaticLocations())
.setCachePeriod(cachePeriod));
}
}
private void registerResourceChain(ResourceHandlerRegistration registration) {
ResourceProperties.Chain properties = this.resourceProperties.getChain();
if (properties.getEnabled()) {
configureResourceChain(properties,
registration.resourceChain(properties.isCache()));
private void customizeResourceHandlerRegistration(ResourceHandlerRegistration registration) {
if (this.resourceHandlerRegistrationCustomizer != null) {
this.resourceHandlerRegistrationCustomizer.customize(registration);
}
}
private void configureResourceChain(ResourceProperties.Chain properties,
ResourceChainRegistration chain) {
Strategy strategy = properties.getStrategy();
if (strategy.getFixed().isEnabled() || strategy.getContent().isEnabled()) {
chain.addResolver(getVersionResourceResolver(strategy));
}
if (properties.isHtmlApplicationCache()) {
chain.addTransformer(new AppCacheManifestTransformer());
}
}
private ResourceResolver getVersionResourceResolver(
ResourceProperties.Strategy properties) {
VersionResourceResolver resolver = new VersionResourceResolver();
if (properties.getFixed().isEnabled()) {
String version = properties.getFixed().getVersion();
String[] paths = properties.getFixed().getPaths();
resolver.addFixedVersionStrategy(version, paths);
}
if (properties.getContent().isEnabled()) {
String[] paths = properties.getContent().getPaths();
resolver.addContentVersionStrategy(paths);
}
return resolver;
}
@Override
@ -380,4 +356,61 @@ public class WebMvcAutoConfiguration {
}
@Configuration
@ConditionalOnEnabledResourceChain
static class ResourceChainCustomizerConfiguration {
@Bean
public ResourceChainResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer() {
return new ResourceChainResourceHandlerRegistrationCustomizer();
}
}
interface ResourceHandlerRegistrationCustomizer {
void customize(ResourceHandlerRegistration registration);
}
private static class ResourceChainResourceHandlerRegistrationCustomizer
implements ResourceHandlerRegistrationCustomizer {
@Autowired
private ResourceProperties resourceProperties = new ResourceProperties();
@Override
public void customize(ResourceHandlerRegistration registration) {
ResourceProperties.Chain properties = this.resourceProperties.getChain();
configureResourceChain(properties,
registration.resourceChain(properties.isCache()));
}
private void configureResourceChain(ResourceProperties.Chain properties,
ResourceChainRegistration chain) {
Strategy strategy = properties.getStrategy();
if (strategy.getFixed().isEnabled() || strategy.getContent().isEnabled()) {
chain.addResolver(getVersionResourceResolver(strategy));
}
if (properties.isHtmlApplicationCache()) {
chain.addTransformer(new AppCacheManifestTransformer());
}
}
private ResourceResolver getVersionResourceResolver(
ResourceProperties.Strategy properties) {
VersionResourceResolver resolver = new VersionResourceResolver();
if (properties.getFixed().isEnabled()) {
String version = properties.getFixed().getVersion();
String[] paths = properties.getFixed().getPaths();
resolver.addFixedVersionStrategy(version, paths);
}
if (properties.getContent().isEnabled()) {
String[] paths = properties.getContent().getPaths();
resolver.addContentVersionStrategy(paths);
}
return resolver;
}
}
}

View File

@ -0,0 +1,58 @@
/*
* 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.autoconfigure.web;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertThat;
/**
* Tests for {@link ResourceProperties}.
*
* @author Stephane Nicoll
*/
public class ResourcePropertiesTest {
private final ResourceProperties properties = new ResourceProperties();
@Test
public void resourceChainNoCustomization() {
System.out.println(this.properties.getChain().getEnabled());
assertThat(this.properties.getChain().getEnabled(), is(nullValue()));
}
@Test
public void resourceChainStrategyEnabled() {
this.properties.getChain().getStrategy().getFixed().setEnabled(true);
assertThat(this.properties.getChain().getEnabled(), is(true));
}
@Test
public void resourceChainEnabled() {
this.properties.getChain().setEnabled(true);
assertThat(this.properties.getChain().getEnabled(), is(true));
}
@Test
public void resourceChainDisabled() {
this.properties.getChain().setEnabled(false);
assertThat(this.properties.getChain().getEnabled(), is(false));
}
}