pull/14847/head
Phillip Webb 7 years ago
parent 67998e983f
commit 7bc535e4fa

@ -95,8 +95,7 @@ public class ControllerEndpointHandlerMapping extends RequestMappingHandlerMappi
ExposableControllerEndpoint endpoint, RequestMappingInfo mapping) { ExposableControllerEndpoint endpoint, RequestMappingInfo mapping) {
Set<PathPattern> patterns = mapping.getPatternsCondition().getPatterns(); Set<PathPattern> patterns = mapping.getPatternsCondition().getPatterns();
if (patterns.isEmpty()) { if (patterns.isEmpty()) {
patterns = new HashSet<>( patterns = new HashSet<>(Arrays.asList(getPathPatternParser().parse("")));
Arrays.asList(getPathPatternParser().parse("")));
} }
PathPattern[] endpointMappedPatterns = patterns.stream() PathPattern[] endpointMappedPatterns = patterns.stream()
.map((pattern) -> getEndpointMappedPattern(endpoint, pattern)) .map((pattern) -> getEndpointMappedPattern(endpoint, pattern))

@ -64,8 +64,8 @@ class DataSourceJmxConfiguration {
public void validateMBeans() { public void validateMBeans() {
HikariDataSource hikariDataSource = unwrapHikariDataSource(); HikariDataSource hikariDataSource = unwrapHikariDataSource();
if (hikariDataSource != null && hikariDataSource.isRegisterMbeans()) { if (hikariDataSource != null && hikariDataSource.isRegisterMbeans()) {
this.mBeanExporter.ifUnique((exporter) -> this.mBeanExporter
exporter.addExcludedBean("dataSource")); .ifUnique((exporter) -> exporter.addExcludedBean("dataSource"));
} }
} }

@ -218,12 +218,10 @@ public class EmbeddedLdapAutoConfiguration {
AnnotatedTypeMetadata metadata) { AnnotatedTypeMetadata metadata) {
Builder message = ConditionMessage.forCondition("Embedded LDAP"); Builder message = ConditionMessage.forCondition("Embedded LDAP");
Environment environment = context.getEnvironment(); Environment environment = context.getEnvironment();
if (environment != null if (environment != null && !Binder.get(environment)
&& !Binder.get(environment)
.bind("spring.ldap.embedded.base-dn", STRING_LIST) .bind("spring.ldap.embedded.base-dn", STRING_LIST)
.orElseGet(Collections::emptyList).isEmpty()) { .orElseGet(Collections::emptyList).isEmpty()) {
return ConditionOutcome return ConditionOutcome.match(message.because("Found base-dn property"));
.match(message.because("Found base-dn property"));
} }
return ConditionOutcome.noMatch(message.because("No base-dn property found")); return ConditionOutcome.noMatch(message.because("No base-dn property found"));
} }

@ -49,18 +49,20 @@ import static org.assertj.core.api.Assertions.assertThat;
public class DataSourceJmxConfigurationTests { public class DataSourceJmxConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withPropertyValues("spring.datasource.url=" .withPropertyValues("spring.datasource.url=" + "jdbc:hsqldb:mem:test-"
+ "jdbc:hsqldb:mem:test-" + UUID.randomUUID()) + UUID.randomUUID())
.withConfiguration(AutoConfigurations.of(JmxAutoConfiguration.class, .withConfiguration(AutoConfigurations.of(JmxAutoConfiguration.class,
DataSourceAutoConfiguration.class)); DataSourceAutoConfiguration.class));
@Test @Test
public void hikariAutoConfiguredCanUseRegisterMBeans() { public void hikariAutoConfiguredCanUseRegisterMBeans() {
String poolName = UUID.randomUUID().toString(); String poolName = UUID.randomUUID().toString();
this.contextRunner.withPropertyValues( this.contextRunner
.withPropertyValues(
"spring.datasource.type=" + HikariDataSource.class.getName(), "spring.datasource.type=" + HikariDataSource.class.getName(),
"spring.datasource.name=" + poolName, "spring.datasource.name=" + poolName,
"spring.datasource.hikari.register-mbeans=true").run((context) -> { "spring.datasource.hikari.register-mbeans=true")
.run((context) -> {
assertThat(context).hasSingleBean(HikariDataSource.class); assertThat(context).hasSingleBean(HikariDataSource.class);
assertThat(context.getBean(HikariDataSource.class).isRegisterMbeans()) assertThat(context.getBean(HikariDataSource.class).isRegisterMbeans())
.isTrue(); .isTrue();
@ -75,33 +77,38 @@ public class DataSourceJmxConfigurationTests {
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer(); MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
Set<ObjectInstance> existingInstances = mBeanServer Set<ObjectInstance> existingInstances = mBeanServer
.queryMBeans(new ObjectName("com.zaxxer.hikari:type=*"), null); .queryMBeans(new ObjectName("com.zaxxer.hikari:type=*"), null);
this.contextRunner.withPropertyValues( this.contextRunner
.withPropertyValues(
"spring.datasource.type=" + HikariDataSource.class.getName(), "spring.datasource.type=" + HikariDataSource.class.getName(),
"spring.datasource.hikari.register-mbeans=true").run((context) -> { "spring.datasource.hikari.register-mbeans=true")
.run((context) -> {
assertThat(context).hasSingleBean(HikariDataSource.class); assertThat(context).hasSingleBean(HikariDataSource.class);
assertThat(context.getBean(HikariDataSource.class).isRegisterMbeans()) assertThat(context.getBean(HikariDataSource.class).isRegisterMbeans())
.isTrue(); .isTrue();
// We can't rely on the number of MBeans so we're checking that the pool and pool // We can't rely on the number of MBeans so we're checking that the
// pool and pool
// config MBeans were registered // config MBeans were registered
assertThat(mBeanServer assertThat(mBeanServer
.queryMBeans(new ObjectName("com.zaxxer.hikari:type=*"), null).size()) .queryMBeans(new ObjectName("com.zaxxer.hikari:type=*"), null)
.isEqualTo(existingInstances.size() + 2); .size()).isEqualTo(existingInstances.size() + 2);
}); });
} }
@Test @Test
public void hikariAutoConfiguredUsesJmsFlag() { public void hikariAutoConfiguredUsesJmsFlag() {
String poolName = UUID.randomUUID().toString(); String poolName = UUID.randomUUID().toString();
this.contextRunner.withPropertyValues( this.contextRunner
.withPropertyValues(
"spring.datasource.type=" + HikariDataSource.class.getName(), "spring.datasource.type=" + HikariDataSource.class.getName(),
"spring.jmx.enabled=false", "spring.datasource.name=" + poolName, "spring.jmx.enabled=false", "spring.datasource.name=" + poolName,
"spring.datasource.hikari.register-mbeans=true").run((context) -> { "spring.datasource.hikari.register-mbeans=true")
.run((context) -> {
assertThat(context).hasSingleBean(HikariDataSource.class); assertThat(context).hasSingleBean(HikariDataSource.class);
assertThat(context.getBean(HikariDataSource.class).isRegisterMbeans()) assertThat(context.getBean(HikariDataSource.class).isRegisterMbeans())
.isTrue(); .isTrue();
// Hikari can still register mBeans // Hikari can still register mBeans
validateHikariMBeansRegistration(ManagementFactory.getPlatformMBeanServer(), validateHikariMBeansRegistration(
poolName, true); ManagementFactory.getPlatformMBeanServer(), poolName, true);
}); });
} }
@ -115,8 +122,9 @@ public class DataSourceJmxConfigurationTests {
"spring.datasource.hikari.register-mbeans=true") "spring.datasource.hikari.register-mbeans=true")
.run((context) -> { .run((context) -> {
assertThat(context).hasSingleBean(javax.sql.DataSource.class); assertThat(context).hasSingleBean(javax.sql.DataSource.class);
HikariDataSource hikariDataSource = context.getBean( HikariDataSource hikariDataSource = context
javax.sql.DataSource.class).unwrap(HikariDataSource.class); .getBean(javax.sql.DataSource.class)
.unwrap(HikariDataSource.class);
assertThat(hikariDataSource.isRegisterMbeans()).isTrue(); assertThat(hikariDataSource.isRegisterMbeans()).isTrue();
MBeanServer mBeanServer = context.getBean(MBeanServer.class); MBeanServer mBeanServer = context.getBean(MBeanServer.class);
validateHikariMBeansRegistration(mBeanServer, poolName, true); validateHikariMBeansRegistration(mBeanServer, poolName, true);
@ -136,9 +144,10 @@ public class DataSourceJmxConfigurationTests {
@Test @Test
public void tomcatDoesNotExposeMBeanPoolByDefault() { public void tomcatDoesNotExposeMBeanPoolByDefault() {
this.contextRunner this.contextRunner
.withPropertyValues("spring.datasource.type=" + DataSource.class.getName()) .withPropertyValues(
.run((context) -> "spring.datasource.type=" + DataSource.class.getName())
assertThat(context).doesNotHaveBean(ConnectionPool.class)); .run((context) -> assertThat(context)
.doesNotHaveBean(ConnectionPool.class));
} }
@Test @Test
@ -147,7 +156,8 @@ public class DataSourceJmxConfigurationTests {
"spring.datasource.type=" + DataSource.class.getName(), "spring.datasource.type=" + DataSource.class.getName(),
"spring.datasource.jmx-enabled=true").run((context) -> { "spring.datasource.jmx-enabled=true").run((context) -> {
assertThat(context).hasSingleBean(ConnectionPool.class); assertThat(context).hasSingleBean(ConnectionPool.class);
assertThat(context.getBean(DataSourceProxy.class).createPool().getJmxPool()) assertThat(context.getBean(DataSourceProxy.class).createPool()
.getJmxPool())
.isSameAs(context.getBean(ConnectionPool.class)); .isSameAs(context.getBean(ConnectionPool.class));
}); });
} }
@ -162,7 +172,6 @@ public class DataSourceJmxConfigurationTests {
} }
private static class DataSourceBeanPostProcessor implements BeanPostProcessor { private static class DataSourceBeanPostProcessor implements BeanPostProcessor {
@Override @Override

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -22,8 +22,6 @@ import java.io.IOException;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import org.assertj.core.api.Condition;
import org.assertj.core.description.Description;
import org.assertj.core.description.TextDescription; import org.assertj.core.description.TextDescription;
import org.springframework.util.FileCopyUtils; import org.springframework.util.FileCopyUtils;

@ -266,8 +266,7 @@ final class JarURLConnection extends java.net.JarURLConnection {
index = separator + SEPARATOR.length(); index = separator + SEPARATOR.length();
} }
JarEntryName jarEntryName = JarEntryName.get(spec, index); JarEntryName jarEntryName = JarEntryName.get(spec, index);
if (Boolean.TRUE.equals(useFastExceptions.get()) if (Boolean.TRUE.equals(useFastExceptions.get()) && !jarEntryName.isEmpty()
&& !jarEntryName.isEmpty()
&& !jarFile.containsEntry(jarEntryName.toString())) { && !jarFile.containsEntry(jarEntryName.toString())) {
return NOT_FOUND_CONNECTION; return NOT_FOUND_CONNECTION;
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

@ -142,8 +142,7 @@ public class ApplicationPidFileWriter
writePidFile(event); writePidFile(event);
} }
catch (Exception ex) { catch (Exception ex) {
String message = String.format("Cannot create pid file %s", String message = String.format("Cannot create pid file %s", this.file);
this.file);
if (failOnWriteError(event)) { if (failOnWriteError(event)) {
throw new IllegalStateException(message, ex); throw new IllegalStateException(message, ex);
} }

@ -16,9 +16,11 @@
package org.springframework.boot.web.embedded.netty; package org.springframework.boot.web.embedded.netty;
import java.util.Arrays;
import java.util.function.BiPredicate; import java.util.function.BiPredicate;
import io.netty.handler.codec.http.HttpHeaderNames; import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaders;
import reactor.ipc.netty.http.server.HttpServerOptions; import reactor.ipc.netty.http.server.HttpServerOptions;
import reactor.ipc.netty.http.server.HttpServerRequest; import reactor.ipc.netty.http.server.HttpServerRequest;
import reactor.ipc.netty.http.server.HttpServerResponse; import reactor.ipc.netty.http.server.HttpServerResponse;
@ -26,11 +28,14 @@ import reactor.ipc.netty.http.server.HttpServerResponse;
import org.springframework.boot.web.server.Compression; import org.springframework.boot.web.server.Compression;
import org.springframework.util.MimeType; import org.springframework.util.MimeType;
import org.springframework.util.MimeTypeUtils; import org.springframework.util.MimeTypeUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/** /**
* Configure the HTTP compression on an Reactor Netty request/response handler. * Configure the HTTP compression on an Reactor Netty request/response handler.
* *
* @author Stephane Maldini * @author Stephane Maldini
* @author Phillip Webb
*/ */
final class CompressionCustomizer implements NettyServerCustomizer { final class CompressionCustomizer implements NettyServerCustomizer {
@ -45,71 +50,46 @@ final class CompressionCustomizer implements NettyServerCustomizer {
if (this.compression.getMinResponseSize() >= 0) { if (this.compression.getMinResponseSize() >= 0) {
builder.compression(this.compression.getMinResponseSize()); builder.compression(this.compression.getMinResponseSize());
} }
BiPredicate<HttpServerRequest, HttpServerResponse> compressPredicate = null; CompressionPredicate mimeTypes = getMimeTypesPredicate(
if (this.compression.getMimeTypes() != null && this.compression.getMimeTypes());
this.compression.getMimeTypes().length > 0) { CompressionPredicate excludedUserAgents = getExcludedUserAgentsPredicate(
compressPredicate = new CompressibleMimeTypePredicate(this.compression.getMimeTypes()); this.compression.getExcludedUserAgents());
} builder.compression(mimeTypes.and(excludedUserAgents));
if (this.compression.getExcludedUserAgents() != null &&
this.compression.getExcludedUserAgents().length > 0) {
BiPredicate<HttpServerRequest, HttpServerResponse> agentCompressPredicate =
new CompressibleAgentPredicate(this.compression.getExcludedUserAgents());
compressPredicate = compressPredicate == null ?
agentCompressPredicate :
compressPredicate.and(agentCompressPredicate);
}
if (compressPredicate != null) {
builder.compression(compressPredicate);
}
} }
private static class CompressibleAgentPredicate private CompressionPredicate getMimeTypesPredicate(String[] mimeTypes) {
implements BiPredicate<HttpServerRequest, HttpServerResponse> { if (ObjectUtils.isEmpty(mimeTypes)) {
return CompressionPredicate.ALWAYS;
private final String[] excludedAgents;
CompressibleAgentPredicate(String[] excludedAgents) {
this.excludedAgents = new String[excludedAgents.length];
System.arraycopy(excludedAgents, 0, this.excludedAgents, 0, excludedAgents.length);
} }
return (request, response) -> {
@Override String contentType = response.responseHeaders()
public boolean test(HttpServerRequest request, HttpServerResponse response) { .get(HttpHeaderNames.CONTENT_TYPE);
for (String excludedAgent : this.excludedAgents) { if (StringUtils.isEmpty(contentType)) {
if (request.requestHeaders()
.contains(HttpHeaderNames.USER_AGENT, excludedAgent, true)) {
return false; return false;
} }
MimeType contentMimeType = MimeTypeUtils.parseMimeType(contentType);
return Arrays.stream(mimeTypes).map(MimeTypeUtils::parseMimeType)
.anyMatch((candidate) -> candidate.isCompatibleWith(contentMimeType));
};
} }
return true;
private CompressionPredicate getExcludedUserAgentsPredicate(
String[] excludedUserAgents) {
if (ObjectUtils.isEmpty(excludedUserAgents)) {
return CompressionPredicate.ALWAYS;
} }
return (request, response) -> {
HttpHeaders headers = request.requestHeaders();
return Arrays.stream(excludedUserAgents).noneMatch((candidate) -> headers
.contains(HttpHeaderNames.USER_AGENT, candidate, true));
};
} }
private static class CompressibleMimeTypePredicate private interface CompressionPredicate
implements BiPredicate<HttpServerRequest, HttpServerResponse> { extends BiPredicate<HttpServerRequest, HttpServerResponse> {
private final MimeType[] mimeTypes; static final CompressionPredicate ALWAYS = (request, response) -> true;
CompressibleMimeTypePredicate(String[] mimeTypes) {
this.mimeTypes = new MimeType[mimeTypes.length];
for (int i = 0; i < mimeTypes.length; i++) {
this.mimeTypes[i] = MimeTypeUtils.parseMimeType(mimeTypes[i]);
}
} }
@Override
public boolean test(HttpServerRequest request, HttpServerResponse response) {
String contentType = response.responseHeaders()
.get(HttpHeaderNames.CONTENT_TYPE);
if (contentType != null) {
for (MimeType mimeType : this.mimeTypes) {
if (mimeType.isCompatibleWith(MimeTypeUtils.parseMimeType(contentType))) {
return true;
}
}
}
return false;
}
}
} }

Loading…
Cancel
Save