Harmonize ConditionOutcome messages
Add ConditionMessage class to help build condition messages in a uniform format and update existing conditions to use it. Fixes gh-6756
This commit is contained in:
parent
41dc53f5dd
commit
7396ccfe04
|
@ -26,6 +26,7 @@ import org.springframework.boot.actuate.endpoint.Endpoint;
|
|||
import org.springframework.boot.actuate.endpoint.jmx.EndpointMBeanExporter;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
||||
|
@ -92,8 +93,13 @@ public class EndpointMBeanExportAutoConfiguration {
|
|||
AnnotatedTypeMetadata metadata) {
|
||||
boolean jmxEnabled = isEnabled(context, "spring.jmx.");
|
||||
boolean jmxEndpointsEnabled = isEnabled(context, "endpoints.jmx.");
|
||||
return new ConditionOutcome(jmxEnabled && jmxEndpointsEnabled,
|
||||
"JMX Endpoints");
|
||||
if (jmxEnabled && jmxEndpointsEnabled) {
|
||||
return ConditionOutcome.match(
|
||||
ConditionMessage.forCondition("JMX Enabled").found("properties")
|
||||
.items("spring.jmx.enabled", "endpoints.jmx.enabled"));
|
||||
}
|
||||
return ConditionOutcome.noMatch(ConditionMessage.forCondition("JMX Enabled")
|
||||
.because("spring.jmx.enabled or endpoints.jmx.enabled is not set"));
|
||||
}
|
||||
|
||||
private boolean isEnabled(ConditionContext context, String prefix) {
|
||||
|
|
|
@ -40,6 +40,7 @@ import org.springframework.boot.actuate.endpoint.mvc.ManagementServletContext;
|
|||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
|
@ -333,13 +334,18 @@ public class EndpointWebMvcAutoConfiguration
|
|||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
ConditionMessage.Builder message = ConditionMessage
|
||||
.forCondition("Management Server MVC");
|
||||
if (!(context.getResourceLoader() instanceof WebApplicationContext)) {
|
||||
return ConditionOutcome.noMatch("Non WebApplicationContext");
|
||||
return ConditionOutcome
|
||||
.noMatch(message.because("non WebApplicationContext"));
|
||||
}
|
||||
ManagementServerPort port = ManagementServerPort.get(context.getEnvironment(),
|
||||
context.getBeanFactory());
|
||||
return new ConditionOutcome(port == ManagementServerPort.SAME,
|
||||
"Management context");
|
||||
if (port == ManagementServerPort.SAME) {
|
||||
return ConditionOutcome.match(message.because("port is same"));
|
||||
}
|
||||
return ConditionOutcome.noMatch(message.because("port is not same"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ import org.springframework.boot.actuate.endpoint.mvc.MetricsMvcEndpoint;
|
|||
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoints;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.ShutdownMvcEndpoint;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
|
@ -182,20 +183,22 @@ public class EndpointWebMvcManagementContextConfiguration {
|
|||
AnnotatedTypeMetadata metadata) {
|
||||
Environment environment = context.getEnvironment();
|
||||
String config = environment.resolvePlaceholders("${logging.file:}");
|
||||
ConditionMessage.Builder message = ConditionMessage
|
||||
.forCondition("Log File");
|
||||
if (StringUtils.hasText(config)) {
|
||||
return ConditionOutcome.match("Found logging.file: " + config);
|
||||
return ConditionOutcome.match(message.found("logging.file").items(config));
|
||||
}
|
||||
config = environment.resolvePlaceholders("${logging.path:}");
|
||||
if (StringUtils.hasText(config)) {
|
||||
return ConditionOutcome.match("Found logging.path: " + config);
|
||||
return ConditionOutcome.match(message.found("logging.path").items(config));
|
||||
}
|
||||
config = new RelaxedPropertyResolver(environment, "endpoints.logfile.")
|
||||
.getProperty("external-file");
|
||||
if (StringUtils.hasText(config)) {
|
||||
return ConditionOutcome
|
||||
.match("Found endpoints.logfile.external-file: " + config);
|
||||
return ConditionOutcome.match(
|
||||
message.found("endpoints.logfile.external-file").items(config));
|
||||
}
|
||||
return ConditionOutcome.noMatch("Found no log file configuration");
|
||||
return ConditionOutcome.noMatch(message.didNotFind("logging file").atAll());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.springframework.boot.actuate.endpoint.mvc.JolokiaMvcEndpoint;
|
|||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
|
@ -97,8 +98,12 @@ public class JolokiaAutoConfiguration {
|
|||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
boolean endpointsEnabled = isEnabled(context, "endpoints.", true);
|
||||
boolean enabled = isEnabled(context, "endpoints.jolokia.", endpointsEnabled);
|
||||
return new ConditionOutcome(enabled, "Jolokia enabled");
|
||||
ConditionMessage.Builder message = ConditionMessage
|
||||
.forCondition("Jolokia");
|
||||
if (isEnabled(context, "endpoints.jolokia.", endpointsEnabled)) {
|
||||
return ConditionOutcome.match(message.because("enabled"));
|
||||
}
|
||||
return ConditionOutcome.noMatch(message.because("not enabled"));
|
||||
}
|
||||
|
||||
private boolean isEnabled(ConditionContext context, String prefix,
|
||||
|
|
|
@ -33,6 +33,7 @@ import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
|
|||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
|
@ -223,10 +224,13 @@ public class ManagementWebSecurityAutoConfiguration {
|
|||
.getProperty("management.security.enabled", "true");
|
||||
String basicEnabled = context.getEnvironment()
|
||||
.getProperty("security.basic.enabled", "true");
|
||||
return new ConditionOutcome(
|
||||
"true".equalsIgnoreCase(managementEnabled)
|
||||
&& !"true".equalsIgnoreCase(basicEnabled),
|
||||
"Management security enabled and basic disabled");
|
||||
ConditionMessage.Builder message = ConditionMessage
|
||||
.forCondition("WebSecurityEnabled");
|
||||
if ("true".equalsIgnoreCase(managementEnabled)
|
||||
&& !"true".equalsIgnoreCase(basicEnabled)) {
|
||||
return ConditionOutcome.match(message.because("security enabled"));
|
||||
}
|
||||
return ConditionOutcome.noMatch(message.because("security disabled"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
|
||||
package org.springframework.boot.actuate.autoconfigure;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
||||
import org.springframework.boot.bind.RelaxedPropertyResolver;
|
||||
|
@ -33,9 +36,10 @@ abstract class OnEnabledEndpointElementCondition extends SpringBootCondition {
|
|||
|
||||
private final String prefix;
|
||||
|
||||
private final Class<?> annotationType;
|
||||
private final Class<? extends Annotation> annotationType;
|
||||
|
||||
OnEnabledEndpointElementCondition(String prefix, Class<?> annotationType) {
|
||||
OnEnabledEndpointElementCondition(String prefix,
|
||||
Class<? extends Annotation> annotationType) {
|
||||
this.prefix = prefix;
|
||||
this.annotationType = annotationType;
|
||||
}
|
||||
|
@ -69,7 +73,8 @@ abstract class OnEnabledEndpointElementCondition extends SpringBootCondition {
|
|||
if (resolver.containsProperty("enabled")) {
|
||||
boolean match = resolver.getProperty("enabled", Boolean.class, true);
|
||||
return new ConditionOutcome(match,
|
||||
getEndpointElementOutcomeMessage(endpointName, match));
|
||||
ConditionMessage.forCondition(this.annotationType).because(
|
||||
this.prefix + endpointName + ".enabled is " + match));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -79,7 +84,8 @@ abstract class OnEnabledEndpointElementCondition extends SpringBootCondition {
|
|||
context.getEnvironment(), this.prefix + "defaults.");
|
||||
boolean match = Boolean.valueOf(resolver.getProperty("enabled", "true"));
|
||||
return new ConditionOutcome(match,
|
||||
getDefaultEndpointElementOutcomeMessage(match));
|
||||
ConditionMessage.forCondition(this.annotationType).because(
|
||||
this.prefix + "defaults.enabled is considered " + match));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
@ -16,6 +16,7 @@
|
|||
|
||||
package org.springframework.boot.actuate.condition;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
||||
import org.springframework.boot.bind.RelaxedPropertyResolver;
|
||||
|
@ -31,14 +32,11 @@ import org.springframework.core.type.AnnotatedTypeMetadata;
|
|||
*/
|
||||
class OnEnabledEndpointCondition extends SpringBootCondition {
|
||||
|
||||
private static final String ANNOTATION_CLASS = ConditionalOnEnabledEndpoint.class
|
||||
.getName();
|
||||
|
||||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
AnnotationAttributes annotationAttributes = AnnotationAttributes
|
||||
.fromMap(metadata.getAnnotationAttributes(ANNOTATION_CLASS));
|
||||
AnnotationAttributes annotationAttributes = AnnotationAttributes.fromMap(metadata
|
||||
.getAnnotationAttributes(ConditionalOnEnabledEndpoint.class.getName()));
|
||||
String endpointName = annotationAttributes.getString("value");
|
||||
boolean enabledByDefault = annotationAttributes.getBoolean("enabledByDefault");
|
||||
ConditionOutcome outcome = determineEndpointOutcome(endpointName,
|
||||
|
@ -56,8 +54,11 @@ class OnEnabledEndpointCondition extends SpringBootCondition {
|
|||
if (resolver.containsProperty("enabled") || !enabledByDefault) {
|
||||
boolean match = resolver.getProperty("enabled", Boolean.class,
|
||||
enabledByDefault);
|
||||
return new ConditionOutcome(match, "The endpoint " + endpointName + " is "
|
||||
+ (match ? "enabled" : "disabled"));
|
||||
ConditionMessage message = ConditionMessage
|
||||
.forCondition(ConditionalOnEnabledEndpoint.class,
|
||||
"(" + endpointName + ")")
|
||||
.because(match ? "enabled" : "disabled");
|
||||
return new ConditionOutcome(match, message);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -66,8 +67,11 @@ class OnEnabledEndpointCondition extends SpringBootCondition {
|
|||
RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(
|
||||
context.getEnvironment(), "endpoints.");
|
||||
boolean match = Boolean.valueOf(resolver.getProperty("enabled", "true"));
|
||||
return new ConditionOutcome(match,
|
||||
"All endpoints are " + (match ? "enabled" : "disabled") + " by default");
|
||||
ConditionMessage message = ConditionMessage
|
||||
.forCondition(ConditionalOnEnabledEndpoint.class)
|
||||
.because("All endpoints are " + (match ? "enabled" : "disabled")
|
||||
+ " by default");
|
||||
return new ConditionOutcome(match, message);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ package org.springframework.boot.autoconfigure;
|
|||
import java.nio.charset.Charset;
|
||||
|
||||
import org.springframework.boot.autoconfigure.MessageSourceAutoConfiguration.ResourceBundleCondition;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
|
||||
|
@ -161,17 +162,19 @@ public class MessageSourceAutoConfiguration {
|
|||
|
||||
private ConditionOutcome getMatchOutcomeForBasename(ConditionContext context,
|
||||
String basename) {
|
||||
ConditionMessage.Builder message = ConditionMessage
|
||||
.forCondition("ResourceBundle");
|
||||
for (String name : StringUtils.commaDelimitedListToStringArray(
|
||||
StringUtils.trimAllWhitespace(basename))) {
|
||||
for (Resource resource : getResources(context.getClassLoader(), name)) {
|
||||
if (resource.exists()) {
|
||||
return ConditionOutcome.match("Bundle found for "
|
||||
+ "spring.messages.basename: " + name);
|
||||
return ConditionOutcome
|
||||
.match(message.found("bundle").items(resource));
|
||||
}
|
||||
}
|
||||
}
|
||||
return ConditionOutcome.noMatch(
|
||||
"No bundle found for " + "spring.messages.basename: " + basename);
|
||||
message.didNotFind("bundle with basename " + basename).atAll());
|
||||
}
|
||||
|
||||
private Resource[] getResources(ClassLoader classLoader, String name) {
|
||||
|
|
|
@ -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.
|
||||
|
@ -16,12 +16,14 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.cache;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
||||
import org.springframework.boot.bind.RelaxedPropertyResolver;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.core.type.ClassMetadata;
|
||||
|
||||
/**
|
||||
* General cache condition used with all cache configuration classes.
|
||||
|
@ -35,18 +37,24 @@ class CacheCondition extends SpringBootCondition {
|
|||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
String sourceClass = "";
|
||||
if (metadata instanceof ClassMetadata) {
|
||||
sourceClass = ((ClassMetadata) metadata).getClassName();
|
||||
}
|
||||
ConditionMessage.Builder message = ConditionMessage.forCondition("Cache",
|
||||
sourceClass);
|
||||
RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(
|
||||
context.getEnvironment(), "spring.cache.");
|
||||
if (!resolver.containsProperty("type")) {
|
||||
return ConditionOutcome.match("Automatic cache type");
|
||||
return ConditionOutcome.match(message.because("automatic cache type"));
|
||||
}
|
||||
CacheType cacheType = CacheConfigurations
|
||||
.getType(((AnnotationMetadata) metadata).getClassName());
|
||||
String value = resolver.getProperty("type").replace("-", "_").toUpperCase();
|
||||
if (value.equals(cacheType.name())) {
|
||||
return ConditionOutcome.match("Cache type " + cacheType);
|
||||
return ConditionOutcome.match(message.because(value + " cache type"));
|
||||
}
|
||||
return ConditionOutcome.noMatch("Cache type " + value);
|
||||
return ConditionOutcome.noMatch(message.because(value + " cache type"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import javax.cache.spi.CachingProvider;
|
|||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
|
@ -177,23 +178,28 @@ class JCacheCacheConfiguration {
|
|||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
ConditionMessage.Builder message = ConditionMessage
|
||||
.forCondition("JCache");
|
||||
RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(
|
||||
context.getEnvironment(), "spring.cache.jcache.");
|
||||
if (resolver.containsProperty("provider")) {
|
||||
return ConditionOutcome.match("JCache provider specified");
|
||||
return ConditionOutcome
|
||||
.match(message.because("JCache provider specified"));
|
||||
}
|
||||
Iterator<CachingProvider> providers = Caching.getCachingProviders()
|
||||
.iterator();
|
||||
if (!providers.hasNext()) {
|
||||
return ConditionOutcome.noMatch("No JSR-107 compliant providers");
|
||||
return ConditionOutcome
|
||||
.noMatch(message.didNotFind("JSR-107 provider").atAll());
|
||||
}
|
||||
providers.next();
|
||||
if (providers.hasNext()) {
|
||||
return ConditionOutcome.noMatch(
|
||||
"Multiple default JSR-107 compliant " + "providers found");
|
||||
return ConditionOutcome
|
||||
.noMatch(message.foundExactly("multiple JSR-107 providers"));
|
||||
|
||||
}
|
||||
return ConditionOutcome.match("Default JSR-107 compliant provider found.");
|
||||
return ConditionOutcome
|
||||
.match(message.foundExactly("single JSR-107 provider"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
@ -35,7 +35,6 @@ import org.springframework.util.Assert;
|
|||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Abstract base class for nested conditions.
|
||||
|
@ -171,16 +170,18 @@ abstract class AbstractNestedCondition extends SpringBootCondition
|
|||
|
||||
private ConditionOutcome getConditionOutcome(AnnotationMetadata metadata,
|
||||
Condition condition) {
|
||||
String messagePrefix = "member condition on " + metadata.getClassName();
|
||||
String className = ClassUtils.getShortName(metadata.getClassName());
|
||||
if (condition instanceof SpringBootCondition) {
|
||||
ConditionOutcome outcome = ((SpringBootCondition) condition)
|
||||
.getMatchOutcome(this.context, metadata);
|
||||
String message = outcome.getMessage();
|
||||
return new ConditionOutcome(outcome.isMatch(), messagePrefix
|
||||
+ (StringUtils.hasLength(message) ? " : " + message : ""));
|
||||
ConditionMessage message = outcome.getConditionMessage()
|
||||
.append("on member " + className);
|
||||
return new ConditionOutcome(outcome.isMatch(), message);
|
||||
}
|
||||
boolean matches = condition.matches(this.context, metadata);
|
||||
return new ConditionOutcome(matches, messagePrefix);
|
||||
return new ConditionOutcome(matches,
|
||||
ConditionMessage.forCondition("NestedCondition")
|
||||
.because("nested on member " + className));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
@ -16,6 +16,9 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.condition;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.context.annotation.Condition;
|
||||
|
||||
/**
|
||||
|
@ -47,11 +50,19 @@ public abstract class AllNestedConditions extends AbstractNestedCondition {
|
|||
|
||||
@Override
|
||||
protected ConditionOutcome getFinalMatchOutcome(MemberMatchOutcomes memberOutcomes) {
|
||||
return new ConditionOutcome(
|
||||
memberOutcomes.getMatches().size() == memberOutcomes.getAll().size(),
|
||||
"nested all match resulted in " + memberOutcomes.getMatches()
|
||||
+ " matches and " + memberOutcomes.getNonMatches()
|
||||
+ " non matches");
|
||||
boolean match = hasSameSize(memberOutcomes.getMatches(), memberOutcomes.getAll());
|
||||
List<ConditionMessage> messages = new ArrayList<ConditionMessage>();
|
||||
messages.add(ConditionMessage.forCondition("AllNestedConditions")
|
||||
.because(memberOutcomes.getMatches().size() + " matched "
|
||||
+ memberOutcomes.getNonMatches().size() + " did not"));
|
||||
for (ConditionOutcome outcome : memberOutcomes.getAll()) {
|
||||
messages.add(outcome.getConditionMessage());
|
||||
}
|
||||
return new ConditionOutcome(match, ConditionMessage.of(messages));
|
||||
}
|
||||
|
||||
private boolean hasSameSize(List<?> list1, List<?> list2) {
|
||||
return list1.size() == list2.size();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
@ -16,6 +16,9 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.condition;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
@ -50,11 +53,15 @@ public abstract class AnyNestedCondition extends AbstractNestedCondition {
|
|||
|
||||
@Override
|
||||
protected ConditionOutcome getFinalMatchOutcome(MemberMatchOutcomes memberOutcomes) {
|
||||
return new ConditionOutcome(!memberOutcomes.getMatches().isEmpty(),
|
||||
"nested any match resulted in " + memberOutcomes.getMatches()
|
||||
+ " matches and " + memberOutcomes.getNonMatches()
|
||||
+ " non matches");
|
||||
|
||||
boolean match = !memberOutcomes.getMatches().isEmpty();
|
||||
List<ConditionMessage> messages = new ArrayList<ConditionMessage>();
|
||||
messages.add(ConditionMessage.forCondition("AnyNestedCondition")
|
||||
.because(memberOutcomes.getMatches().size() + " matched "
|
||||
+ memberOutcomes.getNonMatches().size() + " did not"));
|
||||
for (ConditionOutcome outcome : memberOutcomes.getAll()) {
|
||||
messages.add(outcome.getConditionMessage());
|
||||
}
|
||||
return new ConditionOutcome(match, ConditionMessage.of(messages));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
@ -127,8 +127,8 @@ public final class ConditionEvaluationReport {
|
|||
String prefix = source + "$";
|
||||
for (Entry<String, ConditionAndOutcomes> entry : this.outcomes.entrySet()) {
|
||||
if (entry.getKey().startsWith(prefix)) {
|
||||
ConditionOutcome outcome = new ConditionOutcome(false,
|
||||
"Ancestor '" + source + "' did not match");
|
||||
ConditionOutcome outcome = ConditionOutcome.noMatch(ConditionMessage
|
||||
.forCondition("Ancestor " + source).because("did not match"));
|
||||
entry.getValue().add(ANCESTOR_CONDITION, outcome);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,435 @@
|
|||
/*
|
||||
* 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.condition;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* A message associated with a {@link ConditionOutcome}. Provides a fluent builder style
|
||||
* API to encourage consistency across all condition messages.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 1.4.1
|
||||
*/
|
||||
public final class ConditionMessage {
|
||||
|
||||
private String message;
|
||||
|
||||
private ConditionMessage() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
private ConditionMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
private ConditionMessage(ConditionMessage prior, String message) {
|
||||
this.message = (prior.isEmpty() ? message : prior + "; " + message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@code true} if the message is empty.
|
||||
* @return if the message is empty
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return !StringUtils.hasLength(this.message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return (this.message == null ? "" : this.message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return ObjectUtils.nullSafeHashCode(this.message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null || !ConditionMessage.class.isInstance(obj)) {
|
||||
return false;
|
||||
}
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
return ObjectUtils.nullSafeEquals(((ConditionMessage) obj).message, this.message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@link ConditionMessage} based on the instance and an appended
|
||||
* message.
|
||||
* @param message the message to append
|
||||
* @return a new {@link ConditionMessage} instance
|
||||
*/
|
||||
public ConditionMessage append(String message) {
|
||||
if (!StringUtils.hasLength(message)) {
|
||||
return this;
|
||||
}
|
||||
if (!StringUtils.hasLength(this.message)) {
|
||||
return new ConditionMessage(message);
|
||||
}
|
||||
|
||||
return new ConditionMessage(this.message + " " + message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new builder to construct a new {@link ConditionMessage} based on the
|
||||
* instance and a new condition outcome.
|
||||
* @param condition the condition
|
||||
* @param details details of the condition
|
||||
* @return a {@link Builder} builder
|
||||
* @see #andCondition(String, Object...)
|
||||
* @see #forCondition(Class, Object...)
|
||||
*/
|
||||
public Builder andCondition(Class<? extends Annotation> condition,
|
||||
Object... details) {
|
||||
Assert.notNull(condition, "Condition must not be null");
|
||||
return andCondition("@" + ClassUtils.getShortName(condition), details);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new builder to construct a new {@link ConditionMessage} based on the
|
||||
* instance and a new condition outcome.
|
||||
* @param condition the condition
|
||||
* @param details details of the condition
|
||||
* @return a {@link Builder} builder
|
||||
* @see #andCondition(Class, Object...)
|
||||
* @see #forCondition(String, Object...)
|
||||
*/
|
||||
public Builder andCondition(String condition, Object... details) {
|
||||
Assert.notNull(condition, "Condition must not be null");
|
||||
String detail = StringUtils.arrayToDelimitedString(details, " ");
|
||||
if (StringUtils.hasLength(detail)) {
|
||||
return new Builder(condition + " " + detail);
|
||||
}
|
||||
return new Builder(condition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to return a new empty {@link ConditionMessage}.
|
||||
* @return a new empty {@link ConditionMessage}
|
||||
*/
|
||||
public static ConditionMessage empty() {
|
||||
return new ConditionMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to create a new {@link ConditionMessage} with a specific message.
|
||||
* @param message the source message (may be a format string if {@code args} are
|
||||
* specified
|
||||
* @param args format arguments for the message
|
||||
* @return a new {@link ConditionMessage} instance
|
||||
*/
|
||||
public static ConditionMessage of(String message, Object... args) {
|
||||
if (ObjectUtils.isEmpty(args)) {
|
||||
return new ConditionMessage(message);
|
||||
}
|
||||
return new ConditionMessage(String.format(message, args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to create a new {@link ConditionMessage} comprised of the specified
|
||||
* messages.
|
||||
* @param messages the source messages (may be {@code null}
|
||||
* @return a new {@link ConditionMessage} instance
|
||||
*/
|
||||
public static ConditionMessage of(Collection<? extends ConditionMessage> messages) {
|
||||
ConditionMessage result = new ConditionMessage();
|
||||
if (messages != null) {
|
||||
for (ConditionMessage message : messages) {
|
||||
result = new ConditionMessage(result, message.toString());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method for a builder to construct a new {@link ConditionMessage} for a
|
||||
* condition.
|
||||
* @param condition the condition
|
||||
* @param details details of the condition
|
||||
* @return a {@link Builder} builder
|
||||
* @see #forCondition(String, Object...)
|
||||
* @see #andCondition(String, Object...)
|
||||
*/
|
||||
public static Builder forCondition(Class<? extends Annotation> condition,
|
||||
Object... details) {
|
||||
return new ConditionMessage().andCondition(condition, details);
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method for a builder to construct a new {@link ConditionMessage} for a
|
||||
* condition.
|
||||
* @param condition the condition
|
||||
* @param details details of the condition
|
||||
* @return a {@link Builder} builder
|
||||
* @see #forCondition(Class, Object...)
|
||||
* @see #andCondition(String, Object...)
|
||||
*/
|
||||
public static Builder forCondition(String condition, Object... details) {
|
||||
return new ConditionMessage().andCondition(condition, details);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder used to create a {@link ConditionMessage} for a condition.
|
||||
*/
|
||||
public final class Builder {
|
||||
|
||||
private final String condition;
|
||||
|
||||
private Builder(String condition) {
|
||||
this.condition = condition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that an exact result was found. For example
|
||||
* {@code foundExactly("foo")} results in the message "found foo".
|
||||
* @param result the result that was found
|
||||
* @return a built {@link ConditionMessage}
|
||||
*/
|
||||
public ConditionMessage foundExactly(Object result) {
|
||||
return found("").items(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that one or more results were found. For example
|
||||
* {@code found("bean").items("x")} results in the message "found bean x".
|
||||
* @param article the article found
|
||||
* @return an {@link ItemsBuilder}
|
||||
*/
|
||||
public ItemsBuilder found(String article) {
|
||||
return found(article, article);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that one or more results were found. For example
|
||||
* {@code found("bean", "beans").items("x", "y")} results in the message
|
||||
* "found beans x, y".
|
||||
* @param singular the article found in singular form
|
||||
* @param plural the article found in plural form
|
||||
* @return an {@link ItemsBuilder}
|
||||
*/
|
||||
public ItemsBuilder found(String singular, String plural) {
|
||||
return new ItemsBuilder(this, "found", singular, plural);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that one or more results were not found. For example
|
||||
* {@code didNotFind("bean").items("x")} results in the message
|
||||
* "did not find bean x".
|
||||
* @param article the article found
|
||||
* @return an {@link ItemsBuilder}
|
||||
*/
|
||||
public ItemsBuilder didNotFind(String article) {
|
||||
return didNotFind(article, article);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that one or more results were found. For example
|
||||
* {@code didNotFind("bean", "beans").items("x", "y")} results in the message
|
||||
* "did not find beans x, y".
|
||||
* @param singular the article found in singular form
|
||||
* @param plural the article found in plural form
|
||||
* @return an {@link ItemsBuilder}
|
||||
*/
|
||||
public ItemsBuilder didNotFind(String singular, String plural) {
|
||||
return new ItemsBuilder(this, "did not find", singular, plural);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates a single result. For example {@code resultedIn("yes")} results in the
|
||||
* message "resulted in yes".
|
||||
* @param result the result
|
||||
* @return a built {@link ConditionMessage}
|
||||
*/
|
||||
public ConditionMessage resultedIn(Object result) {
|
||||
return because("resulted in " + result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates something is available. For example {@code available("money")}
|
||||
* results in the message "money is available".
|
||||
* @param item the item that is available
|
||||
* @return a built {@link ConditionMessage}
|
||||
*/
|
||||
public ConditionMessage available(String item) {
|
||||
return because(item + " is available");
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates something is not available. For example {@code notAvailable("time")}
|
||||
* results in the message "time in not available".
|
||||
* @param item the item that is not available
|
||||
* @return a built {@link ConditionMessage}
|
||||
*/
|
||||
public ConditionMessage notAvailable(String item) {
|
||||
return because(item + " is not available");
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates the reason. For example {@code reason("running Linux")} results in
|
||||
* the message "running Linux".
|
||||
* @param reason the reason for the message
|
||||
* @return a built {@link ConditionMessage}
|
||||
*/
|
||||
public ConditionMessage because(String reason) {
|
||||
if (StringUtils.isEmpty(reason)) {
|
||||
return new ConditionMessage(ConditionMessage.this, this.condition);
|
||||
}
|
||||
return new ConditionMessage(ConditionMessage.this,
|
||||
this.condition + " " + reason);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder used to create a {@link ItemsBuilder} for a condition.
|
||||
*/
|
||||
public final class ItemsBuilder {
|
||||
|
||||
private final Builder condition;
|
||||
|
||||
private final String reson;
|
||||
|
||||
private final String singular;
|
||||
|
||||
private final String plural;
|
||||
|
||||
private ItemsBuilder(Builder condition, String reason, String singular,
|
||||
String plural) {
|
||||
this.condition = condition;
|
||||
this.reson = reason;
|
||||
this.singular = singular;
|
||||
this.plural = plural;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used when no items are available. For example
|
||||
* {@code didNotFind("any beans").atAll()} results in the message
|
||||
* "did not find any beans".
|
||||
* @return a built {@link ConditionMessage}
|
||||
*/
|
||||
public ConditionMessage atAll() {
|
||||
return items(Collections.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate the items. For example
|
||||
* {@code didNotFind("bean", "beans").items("x", "y")} results in the message
|
||||
* "did not find beans x, y".
|
||||
* @param items the items (may be {@code null})
|
||||
* @return a built {@link ConditionMessage}
|
||||
*/
|
||||
public ConditionMessage items(Object... items) {
|
||||
return items(Style.NORMAL, items);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate the items. For example
|
||||
* {@code didNotFind("bean", "beans").items("x", "y")} results in the message
|
||||
* "did not find beans x, y".
|
||||
* @param style the render style
|
||||
* @param items the items (may be {@code null})
|
||||
* @return a built {@link ConditionMessage}
|
||||
*/
|
||||
public ConditionMessage items(Style style, Object... items) {
|
||||
return items(style,
|
||||
items == null ? (Collection<?>) null : Arrays.asList(items));
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate the items. For example
|
||||
* {@code didNotFind("bean", "beans").items(Collections.singleton("x")} results in
|
||||
* the message "did not find bean x".
|
||||
* @param items the source of the items (may be {@code null})
|
||||
* @return a built {@link ConditionMessage}
|
||||
*/
|
||||
public ConditionMessage items(Collection<?> items) {
|
||||
return items(Style.NORMAL, items);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate the items. For example
|
||||
* {@code didNotFind("bean", "beans").items(Collections.singleton("x")} results in
|
||||
* the message "did not find bean x".
|
||||
* @param style the render style
|
||||
* @param items the source of the items (may be {@code null})
|
||||
* @return a built {@link ConditionMessage}
|
||||
*/
|
||||
public ConditionMessage items(Style style, Collection<?> items) {
|
||||
Assert.notNull(style, "Style must not be null");
|
||||
StringBuilder message = new StringBuilder(this.reson);
|
||||
items = style.applyTo(items);
|
||||
if ((this.condition == null || items.size() <= 1)
|
||||
&& StringUtils.hasLength(this.singular)) {
|
||||
message.append(" " + this.singular);
|
||||
}
|
||||
else if (StringUtils.hasLength(this.plural)) {
|
||||
message.append(" " + this.plural);
|
||||
}
|
||||
if (items != null && !items.isEmpty()) {
|
||||
message.append(
|
||||
" " + StringUtils.collectionToDelimitedString(items, ", "));
|
||||
}
|
||||
return this.condition.because(message.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Render styles.
|
||||
*/
|
||||
public enum Style {
|
||||
|
||||
NORMAL {
|
||||
@Override
|
||||
protected Object applyToItem(Object item) {
|
||||
return item;
|
||||
}
|
||||
},
|
||||
|
||||
QUOTE {
|
||||
@Override
|
||||
protected String applyToItem(Object item) {
|
||||
return (item == null ? null : "'" + item + "'");
|
||||
}
|
||||
};
|
||||
|
||||
public Collection<?> applyTo(Collection<?> items) {
|
||||
List<Object> result = new ArrayList<Object>();
|
||||
for (Object item : items) {
|
||||
result.add(applyToItem(item));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected abstract Object applyToItem(Object item);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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.
|
||||
|
@ -16,20 +16,38 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.condition;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Outcome for a condition match, including log message.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @see ConditionMessage
|
||||
*/
|
||||
public class ConditionOutcome {
|
||||
|
||||
private final boolean match;
|
||||
|
||||
private final String message;
|
||||
private final ConditionMessage message;
|
||||
|
||||
/**
|
||||
* Create a new {@link ConditionOutcome} instance. For more consistent messages
|
||||
* consider using {@link #ConditionOutcome(boolean, ConditionMessage)}.
|
||||
* @param match if the condition is a match
|
||||
* @param message the condition message
|
||||
*/
|
||||
public ConditionOutcome(boolean match, String message) {
|
||||
this(match, ConditionMessage.of(message));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link ConditionOutcome} instance.
|
||||
* @param match if the condition is a match
|
||||
* @param message the condition message
|
||||
*/
|
||||
public ConditionOutcome(boolean match, ConditionMessage message) {
|
||||
Assert.notNull(message, "ConditionMessage must not be null");
|
||||
this.match = match;
|
||||
this.message = message;
|
||||
}
|
||||
|
@ -39,11 +57,12 @@ public class ConditionOutcome {
|
|||
* @return the {@link ConditionOutcome}
|
||||
*/
|
||||
public static ConditionOutcome match() {
|
||||
return match(null);
|
||||
return match(ConditionMessage.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link ConditionOutcome} instance for 'match'.
|
||||
* Create a new {@link ConditionOutcome} instance for 'match'. For more consistent
|
||||
* messages consider using {@link #match(ConditionMessage)}.
|
||||
* @param message the message
|
||||
* @return the {@link ConditionOutcome}
|
||||
*/
|
||||
|
@ -52,7 +71,17 @@ public class ConditionOutcome {
|
|||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link ConditionOutcome} instance for 'no match'.
|
||||
* Create a new {@link ConditionOutcome} instance for 'match'.
|
||||
* @param message the message
|
||||
* @return the {@link ConditionOutcome}
|
||||
*/
|
||||
public static ConditionOutcome match(ConditionMessage message) {
|
||||
return new ConditionOutcome(true, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link ConditionOutcome} instance for 'no match'. For more consistent
|
||||
* messages consider using {@link #noMatch(ConditionMessage)}.
|
||||
* @param message the message
|
||||
* @return the {@link ConditionOutcome}
|
||||
*/
|
||||
|
@ -60,6 +89,15 @@ public class ConditionOutcome {
|
|||
return new ConditionOutcome(false, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link ConditionOutcome} instance for 'no match'.
|
||||
* @param message the message
|
||||
* @return the {@link ConditionOutcome}
|
||||
*/
|
||||
public static ConditionOutcome noMatch(ConditionMessage message) {
|
||||
return new ConditionOutcome(false, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@code true} if the outcome was a match.
|
||||
* @return {@code true} if the outcome matches
|
||||
|
@ -73,6 +111,14 @@ public class ConditionOutcome {
|
|||
* @return the message or {@code null}
|
||||
*/
|
||||
public String getMessage() {
|
||||
return (this.message.isEmpty() ? null : this.message.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an outcome message or {@code null}.
|
||||
* @return the message or {@code null}
|
||||
*/
|
||||
public ConditionMessage getConditionMessage() {
|
||||
return this.message;
|
||||
}
|
||||
|
||||
|
@ -100,7 +146,7 @@ public class ConditionOutcome {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return (this.message == null ? "" : this.message);
|
||||
return (this.message == null ? "" : this.message.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -110,7 +156,7 @@ public class ConditionOutcome {
|
|||
* @since 1.3.0
|
||||
*/
|
||||
public static ConditionOutcome inverse(ConditionOutcome outcome) {
|
||||
return new ConditionOutcome(!outcome.isMatch(), outcome.getMessage());
|
||||
return new ConditionOutcome(!outcome.isMatch(), outcome.getConditionMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
@ -16,6 +16,9 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.condition;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.context.annotation.Condition;
|
||||
|
||||
/**
|
||||
|
@ -47,10 +50,15 @@ public abstract class NoneNestedConditions extends AbstractNestedCondition {
|
|||
|
||||
@Override
|
||||
protected ConditionOutcome getFinalMatchOutcome(MemberMatchOutcomes memberOutcomes) {
|
||||
return new ConditionOutcome(memberOutcomes.getMatches().isEmpty(),
|
||||
"nested none match resulted in " + memberOutcomes.getMatches()
|
||||
+ " matches and " + memberOutcomes.getNonMatches()
|
||||
+ " non matches");
|
||||
boolean match = memberOutcomes.getMatches().isEmpty();
|
||||
List<ConditionMessage> messages = new ArrayList<ConditionMessage>();
|
||||
messages.add(ConditionMessage.forCondition("NoneNestedConditions")
|
||||
.because(memberOutcomes.getMatches().size() + " matched "
|
||||
+ memberOutcomes.getNonMatches().size() + " did not"));
|
||||
for (ConditionOutcome outcome : memberOutcomes.getAll()) {
|
||||
messages.add(outcome.getConditionMessage());
|
||||
}
|
||||
return new ConditionOutcome(match, ConditionMessage.of(messages));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.springframework.beans.factory.HierarchicalBeanFactory;
|
|||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage.Style;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
|
@ -74,49 +75,52 @@ class OnBeanCondition extends SpringBootCondition implements ConfigurationCondit
|
|||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
StringBuilder matchMessage = new StringBuilder();
|
||||
ConditionMessage matchMessage = ConditionMessage.empty();
|
||||
if (metadata.isAnnotated(ConditionalOnBean.class.getName())) {
|
||||
BeanSearchSpec spec = new BeanSearchSpec(context, metadata,
|
||||
ConditionalOnBean.class);
|
||||
List<String> matching = getMatchingBeans(context, spec);
|
||||
if (matching.isEmpty()) {
|
||||
return ConditionOutcome
|
||||
.noMatch("@ConditionalOnBean " + spec + " found no beans");
|
||||
return ConditionOutcome.noMatch(
|
||||
ConditionMessage.forCondition(ConditionalOnBean.class, spec)
|
||||
.didNotFind("any beans").atAll());
|
||||
}
|
||||
matchMessage.append("@ConditionalOnBean ").append(spec)
|
||||
.append(" found the following ").append(matching);
|
||||
matchMessage = matchMessage.andCondition(ConditionalOnBean.class, spec)
|
||||
.found("bean", "beans").items(Style.QUOTE, matching);
|
||||
}
|
||||
if (metadata.isAnnotated(ConditionalOnSingleCandidate.class.getName())) {
|
||||
BeanSearchSpec spec = new SingleCandidateBeanSearchSpec(context, metadata,
|
||||
ConditionalOnSingleCandidate.class);
|
||||
List<String> matching = getMatchingBeans(context, spec);
|
||||
if (matching.isEmpty()) {
|
||||
return ConditionOutcome.noMatch(
|
||||
"@ConditionalOnSingleCandidate " + spec + " found no beans");
|
||||
return ConditionOutcome.noMatch(ConditionMessage
|
||||
.forCondition(ConditionalOnSingleCandidate.class, spec)
|
||||
.didNotFind("any beans").atAll());
|
||||
}
|
||||
else if (!hasSingleAutowireCandidate(context.getBeanFactory(), matching,
|
||||
spec.getStrategy() == SearchStrategy.ALL)) {
|
||||
return ConditionOutcome.noMatch("@ConditionalOnSingleCandidate " + spec
|
||||
+ " found no primary candidate amongst the" + " following "
|
||||
+ matching);
|
||||
return ConditionOutcome.noMatch(ConditionMessage
|
||||
.forCondition(ConditionalOnSingleCandidate.class, spec)
|
||||
.didNotFind("a primary bean from beans")
|
||||
.items(Style.QUOTE, matching));
|
||||
}
|
||||
matchMessage.append("@ConditionalOnSingleCandidate ").append(spec)
|
||||
.append(" found a primary candidate amongst the following ")
|
||||
.append(matching);
|
||||
matchMessage = matchMessage
|
||||
.andCondition(ConditionalOnSingleCandidate.class, spec)
|
||||
.found("a primary bean from beans").items(Style.QUOTE, matching);
|
||||
}
|
||||
if (metadata.isAnnotated(ConditionalOnMissingBean.class.getName())) {
|
||||
BeanSearchSpec spec = new BeanSearchSpec(context, metadata,
|
||||
ConditionalOnMissingBean.class);
|
||||
List<String> matching = getMatchingBeans(context, spec);
|
||||
if (!matching.isEmpty()) {
|
||||
return ConditionOutcome.noMatch("@ConditionalOnMissingBean " + spec
|
||||
+ " found the following " + matching);
|
||||
return ConditionOutcome.noMatch(ConditionMessage
|
||||
.forCondition(ConditionalOnMissingBean.class, spec)
|
||||
.found("bean", "beans").items(Style.QUOTE, matching));
|
||||
}
|
||||
matchMessage.append(matchMessage.length() == 0 ? "" : " ");
|
||||
matchMessage.append("@ConditionalOnMissingBean ").append(spec)
|
||||
.append(" found no beans");
|
||||
matchMessage = matchMessage.andCondition(ConditionalOnMissingBean.class, spec)
|
||||
.didNotFind("any beans").atAll();
|
||||
}
|
||||
return ConditionOutcome.match(matchMessage.toString());
|
||||
return ConditionOutcome.match(matchMessage);
|
||||
}
|
||||
|
||||
private List<String> getMatchingBeans(ConditionContext context,
|
||||
|
|
|
@ -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.
|
||||
|
@ -21,6 +21,7 @@ import java.util.Iterator;
|
|||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage.Style;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.Ordered;
|
||||
|
@ -28,7 +29,6 @@ import org.springframework.core.annotation.Order;
|
|||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link Condition} that checks for the presence or absence of specific classes.
|
||||
|
@ -43,9 +43,7 @@ class OnClassCondition extends SpringBootCondition {
|
|||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
|
||||
StringBuilder matchMessage = new StringBuilder();
|
||||
|
||||
ConditionMessage matchMessage = ConditionMessage.empty();
|
||||
MultiValueMap<String, Object> onClasses = getAttributes(metadata,
|
||||
ConditionalOnClass.class);
|
||||
if (onClasses != null) {
|
||||
|
@ -53,32 +51,31 @@ class OnClassCondition extends SpringBootCondition {
|
|||
context);
|
||||
if (!missing.isEmpty()) {
|
||||
return ConditionOutcome
|
||||
.noMatch("required @ConditionalOnClass classes not found: "
|
||||
+ StringUtils.collectionToCommaDelimitedString(missing));
|
||||
.noMatch(ConditionMessage.forCondition(ConditionalOnClass.class)
|
||||
.didNotFind("required class", "required classes")
|
||||
.items(Style.QUOTE, missing));
|
||||
}
|
||||
matchMessage.append("@ConditionalOnClass classes found: ")
|
||||
.append(StringUtils.collectionToCommaDelimitedString(
|
||||
getMatchingClasses(onClasses, MatchType.PRESENT, context)));
|
||||
matchMessage = matchMessage.andCondition(ConditionalOnClass.class)
|
||||
.found("required class", "required classes").items(Style.QUOTE,
|
||||
getMatchingClasses(onClasses, MatchType.PRESENT, context));
|
||||
}
|
||||
|
||||
MultiValueMap<String, Object> onMissingClasses = getAttributes(metadata,
|
||||
ConditionalOnMissingClass.class);
|
||||
if (onMissingClasses != null) {
|
||||
List<String> present = getMatchingClasses(onMissingClasses, MatchType.PRESENT,
|
||||
context);
|
||||
if (!present.isEmpty()) {
|
||||
return ConditionOutcome
|
||||
.noMatch("required @ConditionalOnMissing classes found: "
|
||||
+ StringUtils.collectionToCommaDelimitedString(present));
|
||||
return ConditionOutcome.noMatch(
|
||||
ConditionMessage.forCondition(ConditionalOnMissingClass.class)
|
||||
.found("unwanted class", "unwanted classes")
|
||||
.items(Style.QUOTE, present));
|
||||
}
|
||||
matchMessage.append(matchMessage.length() == 0 ? "" : " ");
|
||||
matchMessage.append("@ConditionalOnMissing classes not found: ")
|
||||
.append(StringUtils.collectionToCommaDelimitedString(
|
||||
getMatchingClasses(onMissingClasses, MatchType.MISSING,
|
||||
context)));
|
||||
matchMessage = matchMessage.andCondition(ConditionalOnMissingClass.class)
|
||||
.didNotFind("unwanted class", "unwanted classes")
|
||||
.items(Style.QUOTE, getMatchingClasses(onMissingClasses,
|
||||
MatchType.MISSING, context));
|
||||
}
|
||||
|
||||
return ConditionOutcome.match(matchMessage.toString());
|
||||
return ConditionOutcome.match(matchMessage);
|
||||
}
|
||||
|
||||
private MultiValueMap<String, Object> getAttributes(AnnotatedTypeMetadata metadata,
|
||||
|
@ -111,17 +108,21 @@ class OnClassCondition extends SpringBootCondition {
|
|||
private enum MatchType {
|
||||
|
||||
PRESENT {
|
||||
|
||||
@Override
|
||||
public boolean matches(String className, ConditionContext context) {
|
||||
return ClassUtils.isPresent(className, context.getClassLoader());
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
MISSING {
|
||||
|
||||
@Override
|
||||
public boolean matches(String className, ConditionContext context) {
|
||||
return !ClassUtils.isPresent(className, context.getClassLoader());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
public abstract boolean matches(String className, ConditionContext context);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2013 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,7 +24,6 @@ import org.springframework.context.expression.StandardBeanExpressionResolver;
|
|||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.core.type.ClassMetadata;
|
||||
|
||||
/**
|
||||
* A Condition that evaluates a SpEL expression.
|
||||
|
@ -38,17 +37,11 @@ class OnExpressionCondition extends SpringBootCondition {
|
|||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
|
||||
String expression = (String) metadata
|
||||
.getAnnotationAttributes(ConditionalOnExpression.class.getName())
|
||||
.get("value");
|
||||
expression = wrapIfNecessary(expression);
|
||||
String rawExpression = expression;
|
||||
if (!expression.startsWith("#{")) {
|
||||
// For convenience allow user to provide bare expression with no #{} wrapper
|
||||
expression = "#{" + expression + "}";
|
||||
}
|
||||
|
||||
// Explicitly allow environment placeholders inside the expression
|
||||
expression = context.getEnvironment().resolvePlaceholders(expression);
|
||||
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
|
||||
BeanExpressionResolver resolver = (beanFactory != null)
|
||||
|
@ -59,13 +52,21 @@ class OnExpressionCondition extends SpringBootCondition {
|
|||
resolver = new StandardBeanExpressionResolver();
|
||||
}
|
||||
boolean result = (Boolean) resolver.evaluate(expression, expressionContext);
|
||||
return new ConditionOutcome(result, ConditionMessage
|
||||
.forCondition(ConditionalOnExpression.class, "(" + rawExpression + ")")
|
||||
.resultedIn(result));
|
||||
}
|
||||
|
||||
StringBuilder message = new StringBuilder("SpEL expression");
|
||||
if (metadata instanceof ClassMetadata) {
|
||||
message.append(" on " + ((ClassMetadata) metadata).getClassName());
|
||||
/**
|
||||
* Allow user to provide bare expression with no '#{}' wrapper.
|
||||
* @param expression source expression
|
||||
* @return wrapped expression
|
||||
*/
|
||||
private String wrapIfNecessary(String expression) {
|
||||
if (!expression.startsWith("#{")) {
|
||||
return "#{" + expression + "}";
|
||||
}
|
||||
message.append(": " + rawExpression);
|
||||
return new ConditionOutcome(result, message.toString());
|
||||
return expression;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2014 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.
|
||||
|
@ -52,13 +52,13 @@ class OnJavaCondition extends SpringBootCondition {
|
|||
protected ConditionOutcome getMatchOutcome(Range range, JavaVersion runningVersion,
|
||||
JavaVersion version) {
|
||||
boolean match = runningVersion.isWithin(range, version);
|
||||
return new ConditionOutcome(match, getMessage(range, runningVersion, version));
|
||||
String expected = String.format(
|
||||
range == Range.EQUAL_OR_NEWER ? "(%s or newer)" : "(older than %s)",
|
||||
version);
|
||||
ConditionMessage message = ConditionMessage
|
||||
.forCondition(ConditionalOnJava.class, expected)
|
||||
.foundExactly(runningVersion);
|
||||
return new ConditionOutcome(match, message);
|
||||
}
|
||||
|
||||
private String getMessage(Range range, JavaVersion runningVersion,
|
||||
JavaVersion version) {
|
||||
String expected = String.format(
|
||||
range == Range.EQUAL_OR_NEWER ? "%s or newer" : "older than %s", version);
|
||||
return "Required JVM version " + expected + " found " + runningVersion;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2014 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.
|
||||
|
@ -48,26 +48,33 @@ class OnJndiCondition extends SpringBootCondition {
|
|||
return getMatchOutcome(locations);
|
||||
}
|
||||
catch (NoClassDefFoundError ex) {
|
||||
return ConditionOutcome.noMatch("JNDI class not found");
|
||||
return ConditionOutcome
|
||||
.noMatch(ConditionMessage.forCondition(ConditionalOnJndi.class)
|
||||
.because("JNDI class not found"));
|
||||
}
|
||||
}
|
||||
|
||||
private ConditionOutcome getMatchOutcome(String[] locations) {
|
||||
if (!isJndiAvailable()) {
|
||||
return ConditionOutcome.noMatch("JNDI environment is not available");
|
||||
return ConditionOutcome
|
||||
.noMatch(ConditionMessage.forCondition(ConditionalOnJndi.class)
|
||||
.notAvailable("JNDI environment"));
|
||||
}
|
||||
if (locations.length == 0) {
|
||||
return ConditionOutcome.match("JNDI environment is available");
|
||||
return ConditionOutcome.match(ConditionMessage
|
||||
.forCondition(ConditionalOnJndi.class).available("JNDI environment"));
|
||||
}
|
||||
JndiLocator locator = getJndiLocator(locations);
|
||||
String location = locator.lookupFirstLocation();
|
||||
String details = "(" + StringUtils.arrayToCommaDelimitedString(locations) + ")";
|
||||
if (location != null) {
|
||||
return ConditionOutcome
|
||||
.match("JNDI location '" + location + "' found from candidates "
|
||||
+ StringUtils.arrayToCommaDelimitedString(locations));
|
||||
.match(ConditionMessage.forCondition(ConditionalOnJndi.class, details)
|
||||
.foundExactly("\"" + location + "\""));
|
||||
}
|
||||
return ConditionOutcome.noMatch("No JNDI location found from candidates "
|
||||
+ StringUtils.arrayToCommaDelimitedString(locations));
|
||||
return ConditionOutcome
|
||||
.noMatch(ConditionMessage.forCondition(ConditionalOnJndi.class, details)
|
||||
.didNotFind("any matching JNDI location").atAll());
|
||||
}
|
||||
|
||||
protected boolean isJndiAvailable() {
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage.Style;
|
||||
import org.springframework.boot.bind.RelaxedPropertyResolver;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
|
@ -50,12 +51,17 @@ class OnPropertyCondition extends SpringBootCondition {
|
|||
List<AnnotationAttributes> allAnnotationAttributes = annotationAttributesFromMultiValueMap(
|
||||
metadata.getAllAnnotationAttributes(
|
||||
ConditionalOnProperty.class.getName()));
|
||||
List<ConditionOutcome> noMatchOutcomes = findNoMatchOutcomes(
|
||||
allAnnotationAttributes, context.getEnvironment());
|
||||
if (noMatchOutcomes.isEmpty()) {
|
||||
return ConditionOutcome.match();
|
||||
List<ConditionMessage> noMatch = new ArrayList<ConditionMessage>();
|
||||
List<ConditionMessage> match = new ArrayList<ConditionMessage>();
|
||||
for (AnnotationAttributes annotationAttributes : allAnnotationAttributes) {
|
||||
ConditionOutcome outcome = determineOutcome(annotationAttributes,
|
||||
context.getEnvironment());
|
||||
(outcome.isMatch() ? match : noMatch).add(outcome.getConditionMessage());
|
||||
}
|
||||
return ConditionOutcome.noMatch(getCompositeMessage(noMatchOutcomes));
|
||||
if (!noMatch.isEmpty()) {
|
||||
return ConditionOutcome.noMatch(ConditionMessage.of(noMatch));
|
||||
}
|
||||
return ConditionOutcome.match(ConditionMessage.of(match));
|
||||
}
|
||||
|
||||
private List<AnnotationAttributes> annotationAttributesFromMultiValueMap(
|
||||
|
@ -82,104 +88,110 @@ class OnPropertyCondition extends SpringBootCondition {
|
|||
return annotationAttributes;
|
||||
}
|
||||
|
||||
private List<ConditionOutcome> findNoMatchOutcomes(
|
||||
List<AnnotationAttributes> allAnnotationAttributes,
|
||||
PropertyResolver resolver) {
|
||||
List<ConditionOutcome> noMatchOutcomes = new ArrayList<ConditionOutcome>(
|
||||
allAnnotationAttributes.size());
|
||||
for (AnnotationAttributes annotationAttributes : allAnnotationAttributes) {
|
||||
ConditionOutcome outcome = determineOutcome(annotationAttributes, resolver);
|
||||
if (!outcome.isMatch()) {
|
||||
noMatchOutcomes.add(outcome);
|
||||
}
|
||||
}
|
||||
return noMatchOutcomes;
|
||||
}
|
||||
|
||||
private ConditionOutcome determineOutcome(AnnotationAttributes annotationAttributes,
|
||||
PropertyResolver resolver) {
|
||||
String prefix = annotationAttributes.getString("prefix").trim();
|
||||
if (StringUtils.hasText(prefix) && !prefix.endsWith(".")) {
|
||||
prefix = prefix + ".";
|
||||
}
|
||||
String havingValue = annotationAttributes.getString("havingValue");
|
||||
String[] names = getNames(annotationAttributes);
|
||||
boolean relaxedNames = annotationAttributes.getBoolean("relaxedNames");
|
||||
boolean matchIfMissing = annotationAttributes.getBoolean("matchIfMissing");
|
||||
|
||||
if (relaxedNames) {
|
||||
resolver = new RelaxedPropertyResolver(resolver, prefix);
|
||||
}
|
||||
|
||||
Spec spec = new Spec(annotationAttributes);
|
||||
List<String> missingProperties = new ArrayList<String>();
|
||||
List<String> nonMatchingProperties = new ArrayList<String>();
|
||||
for (String name : names) {
|
||||
String key = (relaxedNames ? name : prefix + name);
|
||||
if (resolver.containsProperty(key)) {
|
||||
if (!isMatch(resolver.getProperty(key), havingValue)) {
|
||||
nonMatchingProperties.add(name);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!matchIfMissing) {
|
||||
missingProperties.add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (missingProperties.isEmpty() && nonMatchingProperties.isEmpty()) {
|
||||
return ConditionOutcome.match();
|
||||
}
|
||||
|
||||
StringBuilder message = new StringBuilder("@ConditionalOnProperty ");
|
||||
spec.collectProperties(resolver, missingProperties, nonMatchingProperties);
|
||||
if (!missingProperties.isEmpty()) {
|
||||
message.append("missing required properties ")
|
||||
.append(expandNames(prefix, missingProperties)).append(" ");
|
||||
return ConditionOutcome.noMatch(
|
||||
ConditionMessage.forCondition(ConditionalOnProperty.class, spec)
|
||||
.didNotFind("property", "properties")
|
||||
.items(Style.QUOTE, missingProperties));
|
||||
}
|
||||
if (!nonMatchingProperties.isEmpty()) {
|
||||
String expected = StringUtils.hasLength(havingValue) ? havingValue : "!false";
|
||||
message.append("expected '").append(expected).append("' for properties ")
|
||||
.append(expandNames(prefix, nonMatchingProperties));
|
||||
return ConditionOutcome.noMatch(
|
||||
ConditionMessage.forCondition(ConditionalOnProperty.class, spec)
|
||||
.found("different value in property",
|
||||
"different value in properties")
|
||||
.items(Style.QUOTE, nonMatchingProperties));
|
||||
}
|
||||
return ConditionOutcome.noMatch(message.toString());
|
||||
return ConditionOutcome.match(ConditionMessage
|
||||
.forCondition(ConditionalOnProperty.class, spec).because("matched"));
|
||||
}
|
||||
|
||||
private String[] getNames(Map<String, Object> annotationAttributes) {
|
||||
String[] value = (String[]) annotationAttributes.get("value");
|
||||
String[] name = (String[]) annotationAttributes.get("name");
|
||||
Assert.state(value.length > 0 || name.length > 0,
|
||||
"The name or value attribute of @ConditionalOnProperty must be specified");
|
||||
Assert.state(value.length == 0 || name.length == 0,
|
||||
"The name and value attributes of @ConditionalOnProperty are exclusive");
|
||||
return (value.length > 0 ? value : name);
|
||||
}
|
||||
private static class Spec {
|
||||
|
||||
private boolean isMatch(String value, String requiredValue) {
|
||||
if (StringUtils.hasLength(requiredValue)) {
|
||||
return requiredValue.equalsIgnoreCase(value);
|
||||
}
|
||||
return !"false".equalsIgnoreCase(value);
|
||||
}
|
||||
private final String prefix;
|
||||
|
||||
private String expandNames(String prefix, List<String> names) {
|
||||
StringBuilder expanded = new StringBuilder();
|
||||
for (String name : names) {
|
||||
expanded.append(expanded.length() == 0 ? "" : ", ");
|
||||
expanded.append(prefix);
|
||||
expanded.append(name);
|
||||
}
|
||||
return expanded.toString();
|
||||
}
|
||||
private final String havingValue;
|
||||
|
||||
private String getCompositeMessage(List<ConditionOutcome> noMatchOutcomes) {
|
||||
StringBuilder message = new StringBuilder();
|
||||
for (ConditionOutcome noMatchOutcome : noMatchOutcomes) {
|
||||
if (message.length() > 0) {
|
||||
message.append(". ");
|
||||
private final String[] names;
|
||||
|
||||
private final boolean relaxedNames;
|
||||
|
||||
private final boolean matchIfMissing;
|
||||
|
||||
Spec(AnnotationAttributes annotationAttributes) {
|
||||
String prefix = annotationAttributes.getString("prefix").trim();
|
||||
if (StringUtils.hasText(prefix) && !prefix.endsWith(".")) {
|
||||
prefix = prefix + ".";
|
||||
}
|
||||
message.append(noMatchOutcome.getMessage().trim());
|
||||
this.prefix = prefix;
|
||||
this.havingValue = annotationAttributes.getString("havingValue");
|
||||
this.names = getNames(annotationAttributes);
|
||||
this.relaxedNames = annotationAttributes.getBoolean("relaxedNames");
|
||||
this.matchIfMissing = annotationAttributes.getBoolean("matchIfMissing");
|
||||
}
|
||||
return message.toString();
|
||||
|
||||
private String[] getNames(Map<String, Object> annotationAttributes) {
|
||||
String[] value = (String[]) annotationAttributes.get("value");
|
||||
String[] name = (String[]) annotationAttributes.get("name");
|
||||
Assert.state(value.length > 0 || name.length > 0,
|
||||
"The name or value attribute of @ConditionalOnProperty must be specified");
|
||||
Assert.state(value.length == 0 || name.length == 0,
|
||||
"The name and value attributes of @ConditionalOnProperty are exclusive");
|
||||
return (value.length > 0 ? value : name);
|
||||
}
|
||||
|
||||
private void collectProperties(PropertyResolver resolver, List<String> missing,
|
||||
List<String> nonMatching) {
|
||||
if (this.relaxedNames) {
|
||||
resolver = new RelaxedPropertyResolver(resolver, this.prefix);
|
||||
}
|
||||
for (String name : this.names) {
|
||||
String key = (this.relaxedNames ? name : this.prefix + name);
|
||||
if (resolver.containsProperty(key)) {
|
||||
if (!isMatch(resolver.getProperty(key), this.havingValue)) {
|
||||
nonMatching.add(name);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!this.matchIfMissing) {
|
||||
missing.add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isMatch(String value, String requiredValue) {
|
||||
if (StringUtils.hasLength(requiredValue)) {
|
||||
return requiredValue.equalsIgnoreCase(value);
|
||||
}
|
||||
return !"false".equalsIgnoreCase(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder result = new StringBuilder();
|
||||
result.append("(");
|
||||
result.append(this.prefix);
|
||||
if (this.names.length == 1) {
|
||||
result.append(this.names[0]);
|
||||
}
|
||||
else {
|
||||
result.append("[");
|
||||
result.append(StringUtils.arrayToCommaDelimitedString(this.names));
|
||||
result.append("]");
|
||||
}
|
||||
if (StringUtils.hasLength(this.havingValue)) {
|
||||
result.append("=").append(this.havingValue);
|
||||
}
|
||||
result.append(")");
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
@ -19,6 +19,7 @@ package org.springframework.boot.autoconfigure.condition;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage.Style;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
|
@ -42,23 +43,28 @@ class OnResourceCondition extends SpringBootCondition {
|
|||
AnnotatedTypeMetadata metadata) {
|
||||
MultiValueMap<String, Object> attributes = metadata
|
||||
.getAllAnnotationAttributes(ConditionalOnResource.class.getName(), true);
|
||||
if (attributes != null) {
|
||||
ResourceLoader loader = context.getResourceLoader() == null
|
||||
? this.defaultResourceLoader : context.getResourceLoader();
|
||||
List<String> locations = new ArrayList<String>();
|
||||
collectValues(locations, attributes.get("resources"));
|
||||
Assert.isTrue(!locations.isEmpty(),
|
||||
"@ConditionalOnResource annotations must specify at least one resource location");
|
||||
for (String location : locations) {
|
||||
if (!loader
|
||||
.getResource(
|
||||
context.getEnvironment().resolvePlaceholders(location))
|
||||
.exists()) {
|
||||
return ConditionOutcome.noMatch("resource not found: " + location);
|
||||
}
|
||||
ResourceLoader loader = context.getResourceLoader() == null
|
||||
? this.defaultResourceLoader : context.getResourceLoader();
|
||||
List<String> locations = new ArrayList<String>();
|
||||
collectValues(locations, attributes.get("resources"));
|
||||
Assert.isTrue(!locations.isEmpty(),
|
||||
"@ConditionalOnResource annotations must specify at "
|
||||
+ "least one resource location");
|
||||
List<String> missing = new ArrayList<String>();
|
||||
for (String location : locations) {
|
||||
String resouce = context.getEnvironment().resolvePlaceholders(location);
|
||||
if (!loader.getResource(resouce).exists()) {
|
||||
missing.add(location);
|
||||
}
|
||||
}
|
||||
return ConditionOutcome.match();
|
||||
if (!missing.isEmpty()) {
|
||||
return ConditionOutcome.noMatch(ConditionMessage
|
||||
.forCondition(ConditionalOnResource.class)
|
||||
.didNotFind("resource", "resources").items(Style.QUOTE, missing));
|
||||
}
|
||||
return ConditionOutcome
|
||||
.match(ConditionMessage.forCondition(ConditionalOnResource.class)
|
||||
.found("location", "locations").items(locations));
|
||||
}
|
||||
|
||||
private void collectValues(List<String> names, List<Object> values) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2014 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.
|
||||
|
@ -43,45 +43,40 @@ class OnWebApplicationCondition extends SpringBootCondition {
|
|||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
boolean webApplicationRequired = metadata
|
||||
boolean required = metadata
|
||||
.isAnnotated(ConditionalOnWebApplication.class.getName());
|
||||
ConditionOutcome webApplication = isWebApplication(context, metadata);
|
||||
|
||||
if (webApplicationRequired && !webApplication.isMatch()) {
|
||||
return ConditionOutcome.noMatch(webApplication.getMessage());
|
||||
ConditionOutcome outcome = isWebApplication(context, metadata, required);
|
||||
if (required && !outcome.isMatch()) {
|
||||
return ConditionOutcome.noMatch(outcome.getConditionMessage());
|
||||
}
|
||||
|
||||
if (!webApplicationRequired && webApplication.isMatch()) {
|
||||
return ConditionOutcome.noMatch(webApplication.getMessage());
|
||||
if (!required && outcome.isMatch()) {
|
||||
return ConditionOutcome.noMatch(outcome.getConditionMessage());
|
||||
}
|
||||
|
||||
return ConditionOutcome.match(webApplication.getMessage());
|
||||
return ConditionOutcome.match(outcome.getConditionMessage());
|
||||
}
|
||||
|
||||
private ConditionOutcome isWebApplication(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
|
||||
AnnotatedTypeMetadata metadata, boolean required) {
|
||||
ConditionMessage.Builder message = ConditionMessage.forCondition(
|
||||
ConditionalOnWebApplication.class, required ? "(required)" : "");
|
||||
if (!ClassUtils.isPresent(WEB_CONTEXT_CLASS, context.getClassLoader())) {
|
||||
return ConditionOutcome.noMatch("web application classes not found");
|
||||
return ConditionOutcome
|
||||
.noMatch(message.didNotFind("web application classes").atAll());
|
||||
}
|
||||
|
||||
if (context.getBeanFactory() != null) {
|
||||
String[] scopes = context.getBeanFactory().getRegisteredScopeNames();
|
||||
if (ObjectUtils.containsElement(scopes, "session")) {
|
||||
return ConditionOutcome.match("found web application 'session' scope");
|
||||
return ConditionOutcome.match(message.foundExactly("'session' scope"));
|
||||
}
|
||||
}
|
||||
|
||||
if (context.getEnvironment() instanceof StandardServletEnvironment) {
|
||||
return ConditionOutcome
|
||||
.match("found web application StandardServletEnvironment");
|
||||
.match(message.foundExactly("StandardServletEnvironment"));
|
||||
}
|
||||
|
||||
if (context.getResourceLoader() instanceof WebApplicationContext) {
|
||||
return ConditionOutcome.match("found web application WebApplicationContext");
|
||||
return ConditionOutcome.match(message.foundExactly("WebApplicationContext"));
|
||||
}
|
||||
|
||||
return ConditionOutcome.noMatch("not a web application");
|
||||
return ConditionOutcome.noMatch(message.because("not a web application"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
@ -16,6 +16,12 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.condition;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage.Builder;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage.Style;
|
||||
import org.springframework.boot.bind.RelaxedPropertyResolver;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
@ -61,8 +67,8 @@ public abstract class ResourceCondition extends SpringBootCondition {
|
|||
RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(
|
||||
context.getEnvironment(), this.prefix);
|
||||
if (resolver.containsProperty(this.propertyName)) {
|
||||
return ConditionOutcome.match("A '" + this.prefix + this.propertyName + "' "
|
||||
+ "property is specified");
|
||||
return ConditionOutcome.match(startConditionMessage()
|
||||
.foundExactly("property " + this.prefix + this.propertyName));
|
||||
}
|
||||
return getResourceOutcome(context, metadata);
|
||||
}
|
||||
|
@ -75,15 +81,26 @@ public abstract class ResourceCondition extends SpringBootCondition {
|
|||
*/
|
||||
protected ConditionOutcome getResourceOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
List<String> found = new ArrayList<String>();
|
||||
for (String location : this.resourceLocations) {
|
||||
Resource resource = context.getResourceLoader().getResource(location);
|
||||
if (resource != null && resource.exists()) {
|
||||
return ConditionOutcome
|
||||
.match("Found " + this.name + " config in " + resource);
|
||||
found.add(location);
|
||||
}
|
||||
}
|
||||
return ConditionOutcome
|
||||
.noMatch("No specific " + this.name + " configuration found");
|
||||
if (found.isEmpty()) {
|
||||
ConditionMessage message = startConditionMessage()
|
||||
.didNotFind("resource", "resources")
|
||||
.items(Style.QUOTE, Arrays.asList(this.resourceLocations));
|
||||
return ConditionOutcome.noMatch(message);
|
||||
}
|
||||
ConditionMessage message = startConditionMessage().found("resource", "resources")
|
||||
.items(Style.QUOTE, found);
|
||||
return ConditionOutcome.match(message);
|
||||
}
|
||||
|
||||
protected final Builder startConditionMessage() {
|
||||
return ConditionMessage.forCondition("ResourceCondition", "(" + this.name + ")");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
@ -43,8 +43,8 @@ public abstract class HazelcastConfigResourceCondition extends ResourceCondition
|
|||
protected ConditionOutcome getResourceOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
if (System.getProperty(CONFIG_SYSTEM_PROPERTY) != null) {
|
||||
return ConditionOutcome
|
||||
.match("System property '" + CONFIG_SYSTEM_PROPERTY + "' is set.");
|
||||
return ConditionOutcome.match(startConditionMessage()
|
||||
.because("System property '" + CONFIG_SYSTEM_PROPERTY + "' is set."));
|
||||
}
|
||||
return super.getResourceOutcome(context, metadata);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import java.io.IOException;
|
|||
import java.util.Properties;
|
||||
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnResource;
|
||||
|
@ -104,9 +105,13 @@ public class ProjectInfoAutoConfiguration {
|
|||
location = "classpath:git.properties";
|
||||
}
|
||||
}
|
||||
boolean match = loader.getResource(location).exists();
|
||||
return new ConditionOutcome(match,
|
||||
"Git info " + (match ? "found" : "not found") + " at " + location);
|
||||
ConditionMessage.Builder message = ConditionMessage
|
||||
.forCondition("GitResource");
|
||||
if (loader.getResource(location).exists()) {
|
||||
return ConditionOutcome.match(message.found("git info at").items(location));
|
||||
}
|
||||
return ConditionOutcome
|
||||
.noMatch(message.didNotFind("git info at").items(location));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.springframework.beans.factory.config.BeanDefinition;
|
|||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
|
@ -156,10 +157,14 @@ public class DataSourceAutoConfiguration {
|
|||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
ConditionMessage.Builder message = ConditionMessage
|
||||
.forCondition("PooledDataSource");
|
||||
if (getDataSourceClassLoader(context) != null) {
|
||||
return ConditionOutcome.match("supported DataSource class found");
|
||||
return ConditionOutcome
|
||||
.match(message.foundExactly("supported DataSource"));
|
||||
}
|
||||
return ConditionOutcome.noMatch("missing supported DataSource");
|
||||
return ConditionOutcome
|
||||
.noMatch(message.didNotFind("supported DataSource").atAll());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -187,15 +192,19 @@ public class DataSourceAutoConfiguration {
|
|||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
ConditionMessage.Builder message = ConditionMessage
|
||||
.forCondition("EmbeddedDataSource");
|
||||
if (anyMatches(context, metadata, this.pooledCondition)) {
|
||||
return ConditionOutcome.noMatch("supported DataSource class found");
|
||||
return ConditionOutcome
|
||||
.noMatch(message.foundExactly("supported pooled data source"));
|
||||
}
|
||||
EmbeddedDatabaseType type = EmbeddedDatabaseConnection
|
||||
.get(context.getClassLoader()).getType();
|
||||
if (type == null) {
|
||||
return ConditionOutcome.noMatch("no embedded database detected");
|
||||
return ConditionOutcome
|
||||
.noMatch(message.didNotFind("embedded database").atAll());
|
||||
}
|
||||
return ConditionOutcome.match("embedded database " + type + " detected");
|
||||
return ConditionOutcome.match(message.found("embedded database").items(type));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -214,16 +223,20 @@ public class DataSourceAutoConfiguration {
|
|||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
ConditionMessage.Builder message = ConditionMessage
|
||||
.forCondition("EmbeddedDataAvailble");
|
||||
if (hasBean(context, DataSource.class)
|
||||
|| hasBean(context, XADataSource.class)) {
|
||||
return ConditionOutcome
|
||||
.match("existing bean configured database detected");
|
||||
.match(message.foundExactly("existing database bean"));
|
||||
}
|
||||
if (anyMatches(context, metadata, this.pooledCondition,
|
||||
this.embeddedCondition)) {
|
||||
return ConditionOutcome.match("existing auto database detected");
|
||||
return ConditionOutcome
|
||||
.match(message.foundExactly("existing auto-configured database"));
|
||||
}
|
||||
return ConditionOutcome.noMatch("no existing bean configured database");
|
||||
return ConditionOutcome
|
||||
.noMatch(message.didNotFind("any existing data source bean").atAll());
|
||||
}
|
||||
|
||||
private boolean hasBean(ConditionContext context, Class<?> type) {
|
||||
|
|
|
@ -116,8 +116,9 @@ public class ConditionEvaluationReportMessage {
|
|||
.append(String.format("%n"));
|
||||
for (ConditionAndOutcome conditionAndOutcome : conditionAndOutcomes) {
|
||||
message.append(" - ");
|
||||
if (StringUtils.hasLength(conditionAndOutcome.getOutcome().getMessage())) {
|
||||
message.append(conditionAndOutcome.getOutcome().getMessage());
|
||||
String outcomeMessage = conditionAndOutcome.getOutcome().getMessage();
|
||||
if (StringUtils.hasLength(outcomeMessage)) {
|
||||
message.append(outcomeMessage);
|
||||
}
|
||||
else {
|
||||
message.append(conditionAndOutcome.getOutcome().isMatch() ? "matched"
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.orm.jpa;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -28,6 +29,8 @@ import org.apache.commons.logging.LogFactory;
|
|||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage.Style;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
||||
|
@ -199,13 +202,18 @@ public class HibernateJpaAutoConfiguration extends JpaBaseConfiguration {
|
|||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
ConditionMessage.Builder message = ConditionMessage
|
||||
.forCondition("HibernateEntityManager");
|
||||
for (String className : CLASS_NAMES) {
|
||||
if (ClassUtils.isPresent(className, context.getClassLoader())) {
|
||||
return ConditionOutcome.match("found HibernateEntityManager class");
|
||||
return ConditionOutcome
|
||||
.match(message.found("class").items(Style.QUOTE, className));
|
||||
}
|
||||
}
|
||||
return ConditionOutcome.noMatch("did not find HibernateEntityManager class");
|
||||
return ConditionOutcome.noMatch(message.didNotFind("class", "classes")
|
||||
.items(Style.QUOTE, Arrays.asList(CLASS_NAMES)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* 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.security.oauth2.client;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
|
||||
/**
|
||||
* Condition that checks for {@link EnableOAuth2Sso} on a
|
||||
* {@link WebSecurityConfigurerAdapter}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
class EnableOAuth2SsoCondition extends SpringBootCondition {
|
||||
|
||||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
String[] enablers = context.getBeanFactory()
|
||||
.getBeanNamesForAnnotation(EnableOAuth2Sso.class);
|
||||
ConditionMessage.Builder message = ConditionMessage
|
||||
.forCondition("@EnableOAuth2Sso Condition");
|
||||
for (String name : enablers) {
|
||||
if (context.getBeanFactory().isTypeMatch(name,
|
||||
WebSecurityConfigurerAdapter.class)) {
|
||||
return ConditionOutcome.match(message
|
||||
.found("@EnableOAuth2Sso annotation on WebSecurityConfigurerAdapter")
|
||||
.items(name));
|
||||
}
|
||||
}
|
||||
return ConditionOutcome.noMatch(message.didNotFind(
|
||||
"@EnableOAuth2Sso annotation " + "on any WebSecurityConfigurerAdapter")
|
||||
.atAll());
|
||||
}
|
||||
|
||||
}
|
|
@ -19,6 +19,7 @@ package org.springframework.boot.autoconfigure.security.oauth2.client;
|
|||
import javax.annotation.Resource;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
|
@ -161,8 +162,14 @@ public class OAuth2RestOperationsConfiguration {
|
|||
PropertyResolver resolver = new RelaxedPropertyResolver(
|
||||
context.getEnvironment(), "security.oauth2.client.");
|
||||
String clientId = resolver.getProperty("client-id");
|
||||
return new ConditionOutcome(StringUtils.hasLength(clientId),
|
||||
"Non empty security.oauth2.client.client-id");
|
||||
ConditionMessage.Builder message = ConditionMessage
|
||||
.forCondition("OAuth Client ID");
|
||||
if (StringUtils.hasLength(clientId)) {
|
||||
return ConditionOutcome.match(message
|
||||
.foundExactly("security.oauth2.client.client-id property"));
|
||||
}
|
||||
return ConditionOutcome.match(message
|
||||
.didNotFind("security.oauth2.client.client-id property").atAll());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,16 +24,11 @@ import org.aopalliance.intercept.MethodInvocation;
|
|||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2SsoCustomConfiguration.WebSecurityEnhancerCondition;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.ImportAware;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
|
@ -49,7 +44,7 @@ import org.springframework.util.ReflectionUtils;
|
|||
* @author Dave Syer
|
||||
*/
|
||||
@Configuration
|
||||
@Conditional(WebSecurityEnhancerCondition.class)
|
||||
@Conditional(EnableOAuth2SsoCondition.class)
|
||||
public class OAuth2SsoCustomConfiguration
|
||||
implements ImportAware, BeanPostProcessor, ApplicationContextAware {
|
||||
|
||||
|
@ -111,24 +106,4 @@ public class OAuth2SsoCustomConfiguration
|
|||
|
||||
}
|
||||
|
||||
protected static class WebSecurityEnhancerCondition extends SpringBootCondition {
|
||||
|
||||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
String[] enablers = context.getBeanFactory()
|
||||
.getBeanNamesForAnnotation(EnableOAuth2Sso.class);
|
||||
for (String name : enablers) {
|
||||
if (context.getBeanFactory().isTypeMatch(name,
|
||||
WebSecurityConfigurerAdapter.class)) {
|
||||
return ConditionOutcome.match(
|
||||
"found @EnableOAuth2Sso on a WebSecurityConfigurerAdapter");
|
||||
}
|
||||
}
|
||||
return ConditionOutcome.noMatch(
|
||||
"found no @EnableOAuth2Sso on a WebSecurityConfigurerAdapter");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
package org.springframework.boot.autoconfigure.security.oauth2.client;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2SsoDefaultConfiguration.NeedsWebSecurityCondition;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
@ -75,22 +74,12 @@ public class OAuth2SsoDefaultConfiguration extends WebSecurityConfigurerAdapter
|
|||
return SecurityProperties.ACCESS_OVERRIDE_ORDER;
|
||||
}
|
||||
|
||||
protected static class NeedsWebSecurityCondition extends SpringBootCondition {
|
||||
protected static class NeedsWebSecurityCondition extends EnableOAuth2SsoCondition {
|
||||
|
||||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
String[] enablers = context.getBeanFactory()
|
||||
.getBeanNamesForAnnotation(EnableOAuth2Sso.class);
|
||||
for (String name : enablers) {
|
||||
if (context.getBeanFactory().isTypeMatch(name,
|
||||
WebSecurityConfigurerAdapter.class)) {
|
||||
return ConditionOutcome.noMatch(
|
||||
"found @EnableOAuth2Sso on a WebSecurityConfigurerAdapter");
|
||||
}
|
||||
}
|
||||
return ConditionOutcome
|
||||
.match("found no @EnableOAuth2Sso on a WebSecurityConfigurerAdapter");
|
||||
return ConditionOutcome.inverse(super.getMatchOutcome(context, metadata));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package org.springframework.boot.autoconfigure.security.oauth2.resource;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
|
@ -112,28 +113,32 @@ public class OAuth2ResourceServerConfiguration {
|
|||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
ConditionMessage.Builder message = ConditionMessage
|
||||
.forCondition("OAuth ResourceServer Condition");
|
||||
Environment environment = context.getEnvironment();
|
||||
RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(environment,
|
||||
"security.oauth2.resource.");
|
||||
if (hasOAuthClientId(environment)) {
|
||||
return ConditionOutcome.match("found client id");
|
||||
return ConditionOutcome.match(message.foundExactly("client-id property"));
|
||||
}
|
||||
if (!resolver.getSubProperties("jwt").isEmpty()) {
|
||||
return ConditionOutcome.match("found JWT resource configuration");
|
||||
return ConditionOutcome
|
||||
.match(message.foundExactly("JWT resource configuration"));
|
||||
}
|
||||
if (StringUtils.hasText(resolver.getProperty("user-info-uri"))) {
|
||||
return ConditionOutcome
|
||||
.match("found UserInfo " + "URI resource configuration");
|
||||
.match(message.foundExactly("user-info-url property"));
|
||||
}
|
||||
if (ClassUtils.isPresent(AUTHORIZATION_ANNOTATION, null)) {
|
||||
if (AuthorizationServerEndpointsConfigurationBeanCondition
|
||||
.matches(context)) {
|
||||
return ConditionOutcome.match(
|
||||
"found authorization " + "server endpoints configuration");
|
||||
return ConditionOutcome
|
||||
.match(message.found("class").items(AUTHORIZATION_ANNOTATION));
|
||||
}
|
||||
}
|
||||
return ConditionOutcome.noMatch("found neither client id nor "
|
||||
+ "JWT resource nor authorization server");
|
||||
return ConditionOutcome.noMatch(
|
||||
message.didNotFind("client id, JWT resource or authorization server")
|
||||
.atAll());
|
||||
}
|
||||
|
||||
private boolean hasOAuthClientId(Environment environment) {
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.apache.commons.logging.Log;
|
|||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
|
@ -292,6 +293,8 @@ public class ResourceServerTokenServicesConfiguration {
|
|||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
ConditionMessage.Builder message = ConditionMessage
|
||||
.forCondition("OAuth TokenInfo Condition");
|
||||
Environment environment = context.getEnvironment();
|
||||
RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(environment,
|
||||
"security.oauth2.resource.");
|
||||
|
@ -305,13 +308,14 @@ public class ResourceServerTokenServicesConfiguration {
|
|||
String tokenInfoUri = resolver.getProperty("token-info-uri");
|
||||
String userInfoUri = resolver.getProperty("user-info-uri");
|
||||
if (!StringUtils.hasLength(userInfoUri)) {
|
||||
return ConditionOutcome.match("No user info provided");
|
||||
return ConditionOutcome
|
||||
.match(message.didNotFind("user-info-uri property").atAll());
|
||||
}
|
||||
if (StringUtils.hasLength(tokenInfoUri) && preferTokenInfo) {
|
||||
return ConditionOutcome.match(
|
||||
"Token info endpoint " + "is preferred and user info provided");
|
||||
return ConditionOutcome
|
||||
.match(message.foundExactly("preferred token-info-uri property"));
|
||||
}
|
||||
return ConditionOutcome.noMatch("Token info endpoint is not provided");
|
||||
return ConditionOutcome.noMatch(message.didNotFind("token info").atAll());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -321,14 +325,18 @@ public class ResourceServerTokenServicesConfiguration {
|
|||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
ConditionMessage.Builder message = ConditionMessage
|
||||
.forCondition("OAuth JWT Condition");
|
||||
RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(
|
||||
context.getEnvironment(), "security.oauth2.resource.jwt.");
|
||||
String keyValue = resolver.getProperty("key-value");
|
||||
String keyUri = resolver.getProperty("key-uri");
|
||||
if (StringUtils.hasText(keyValue) || StringUtils.hasText(keyUri)) {
|
||||
return ConditionOutcome.match("public key is provided");
|
||||
return ConditionOutcome
|
||||
.match(message.foundExactly("provided public key"));
|
||||
}
|
||||
return ConditionOutcome.noMatch("public key is not provided");
|
||||
return ConditionOutcome
|
||||
.noMatch(message.didNotFind("provided public key").atAll());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.session;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
||||
import org.springframework.boot.bind.RelaxedPropertyResolver;
|
||||
|
@ -38,22 +39,27 @@ class SessionCondition extends SpringBootCondition {
|
|||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
ConditionMessage.Builder message = ConditionMessage
|
||||
.forCondition("Session Condition");
|
||||
RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(
|
||||
context.getEnvironment(), "spring.session.");
|
||||
StoreType sessionStoreType = SessionStoreMappings
|
||||
.getType(((AnnotationMetadata) metadata).getClassName());
|
||||
if (!resolver.containsProperty("store-type")) {
|
||||
if (sessionStoreType == StoreType.REDIS && redisPresent) {
|
||||
return ConditionOutcome
|
||||
.match("Session store type default to redis (deprecated)");
|
||||
return ConditionOutcome.match(
|
||||
message.foundExactly("default store type of redis (deprecated)"));
|
||||
}
|
||||
return ConditionOutcome.noMatch("Session store type not set");
|
||||
return ConditionOutcome.noMatch(
|
||||
message.didNotFind("spring.session.store-type property").atAll());
|
||||
}
|
||||
String value = resolver.getProperty("store-type").replace("-", "_").toUpperCase();
|
||||
if (value.equals(sessionStoreType.name())) {
|
||||
return ConditionOutcome.match("Session store type " + sessionStoreType);
|
||||
return ConditionOutcome.match(message
|
||||
.found("spring.session.store-type property").items(sessionStoreType));
|
||||
}
|
||||
return ConditionOutcome.noMatch("Session store type " + value);
|
||||
return ConditionOutcome
|
||||
.noMatch(message.found("spring.session.store-type property").items(value));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,6 +27,8 @@ import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
|||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage.Style;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
|
@ -153,23 +155,28 @@ public class DispatcherServletAutoConfiguration {
|
|||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
ConditionMessage.Builder message = ConditionMessage
|
||||
.forCondition("Default DispatcherServlet");
|
||||
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
|
||||
List<String> dispatchServletBeans = Arrays.asList(beanFactory
|
||||
.getBeanNamesForType(DispatcherServlet.class, false, false));
|
||||
if (dispatchServletBeans.contains(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)) {
|
||||
return ConditionOutcome.noMatch("found DispatcherServlet named "
|
||||
+ DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
|
||||
return ConditionOutcome.noMatch(message.found("dispatcher servlet bean")
|
||||
.items(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME));
|
||||
}
|
||||
if (beanFactory.containsBean(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)) {
|
||||
return ConditionOutcome.noMatch("found non-DispatcherServlet named "
|
||||
+ DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
|
||||
return ConditionOutcome
|
||||
.noMatch(message.found("non dispatcher servlet bean")
|
||||
.items(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME));
|
||||
}
|
||||
if (dispatchServletBeans.isEmpty()) {
|
||||
return ConditionOutcome.match("no DispatcherServlet found");
|
||||
return ConditionOutcome
|
||||
.match(message.didNotFind("dispatcher servlet beans").atAll());
|
||||
}
|
||||
return ConditionOutcome
|
||||
.match("one or more DispatcherServlets found and none is named "
|
||||
+ DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
|
||||
return ConditionOutcome.match(message
|
||||
.found("dipatcher servlet bean", "dispatcher servlet beans")
|
||||
.items(Style.QUOTE, dispatchServletBeans)
|
||||
.append("and none is named " + DEFAULT_DISPATCHER_SERVLET_BEAN_NAME));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -197,39 +204,48 @@ public class DispatcherServletAutoConfiguration {
|
|||
.containsBean(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
|
||||
if (containsDispatcherBean
|
||||
&& !servlets.contains(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)) {
|
||||
return ConditionOutcome.noMatch("found non-DispatcherServlet named "
|
||||
+ DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
|
||||
return ConditionOutcome
|
||||
.noMatch(startMessage().found("non dispatcher servlet")
|
||||
.items(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME));
|
||||
}
|
||||
return ConditionOutcome.match();
|
||||
}
|
||||
|
||||
private ConditionOutcome checkServletRegistration(
|
||||
ConfigurableListableBeanFactory beanFactory) {
|
||||
ConditionMessage.Builder message = startMessage();
|
||||
List<String> registrations = Arrays.asList(beanFactory
|
||||
.getBeanNamesForType(ServletRegistrationBean.class, false, false));
|
||||
boolean containsDispatcherRegistrationBean = beanFactory
|
||||
.containsBean(DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME);
|
||||
if (registrations.isEmpty()) {
|
||||
if (containsDispatcherRegistrationBean) {
|
||||
return ConditionOutcome.noMatch("found no ServletRegistrationBean "
|
||||
+ "but a non-ServletRegistrationBean named "
|
||||
+ DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME);
|
||||
return ConditionOutcome
|
||||
.noMatch(message.found("non servlet registration bean").items(
|
||||
DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME));
|
||||
}
|
||||
return ConditionOutcome.match("no ServletRegistrationBean found");
|
||||
return ConditionOutcome
|
||||
.match(message.didNotFind("servlet registration bean").atAll());
|
||||
}
|
||||
if (registrations
|
||||
.contains(DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)) {
|
||||
return ConditionOutcome.noMatch("found ServletRegistrationBean named "
|
||||
+ DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME);
|
||||
return ConditionOutcome.noMatch(message.found("servlet registration bean")
|
||||
.items(DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME));
|
||||
}
|
||||
if (containsDispatcherRegistrationBean) {
|
||||
return ConditionOutcome.noMatch("found non-ServletRegistrationBean named "
|
||||
+ DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME);
|
||||
return ConditionOutcome
|
||||
.noMatch(message.found("non servlet registration bean").items(
|
||||
DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME));
|
||||
}
|
||||
return ConditionOutcome
|
||||
.match("one or more ServletRegistrationBeans is found and none is named "
|
||||
+ DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME);
|
||||
return ConditionOutcome.match(message.found("servlet registration beans")
|
||||
.items(Style.QUOTE, registrations).append("and none is named "
|
||||
+ DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME));
|
||||
}
|
||||
|
||||
private ConditionMessage.Builder startMessage() {
|
||||
return ConditionMessage.forCondition("DispatcherServlet Registration");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
|||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
|
@ -166,6 +167,8 @@ public class ErrorMvcAutoConfiguration {
|
|||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
ConditionMessage.Builder message = ConditionMessage
|
||||
.forCondition("ErrorTemplate Misssing");
|
||||
TemplateAvailabilityProviders providers = new TemplateAvailabilityProviders(
|
||||
context.getClassLoader());
|
||||
TemplateAvailabilityProvider provider = providers.getProvider("error",
|
||||
|
@ -173,9 +176,10 @@ public class ErrorMvcAutoConfiguration {
|
|||
context.getResourceLoader());
|
||||
if (provider != null) {
|
||||
return ConditionOutcome
|
||||
.noMatch("Template from " + provider + " found for error view");
|
||||
.noMatch(message.foundExactly("template from " + provider));
|
||||
}
|
||||
return ConditionOutcome.match("No error template view detected");
|
||||
return ConditionOutcome
|
||||
.match(message.didNotFind("error template view").atAll());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.web;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
||||
import org.springframework.boot.bind.PropertySourcesPropertyValues;
|
||||
|
@ -31,6 +32,7 @@ import org.springframework.util.ClassUtils;
|
|||
* enabled.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @see ConditionalOnEnabledResourceChain
|
||||
*/
|
||||
class OnEnabledResourceChainCondition extends SpringBootCondition {
|
||||
|
||||
|
@ -45,15 +47,21 @@ class OnEnabledResourceChainCondition extends SpringBootCondition {
|
|||
RelaxedDataBinder binder = new RelaxedDataBinder(properties, "spring.resources");
|
||||
binder.bind(new PropertySourcesPropertyValues(environment.getPropertySources()));
|
||||
Boolean match = properties.getChain().getEnabled();
|
||||
ConditionMessage.Builder message = ConditionMessage
|
||||
.forCondition(ConditionalOnEnabledResourceChain.class);
|
||||
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"));
|
||||
if (ClassUtils.isPresent(WEBJAR_ASSERT_LOCATOR,
|
||||
getClass().getClassLoader())) {
|
||||
return ConditionOutcome
|
||||
.match(message.found("class").items(WEBJAR_ASSERT_LOCATOR));
|
||||
}
|
||||
return ConditionOutcome
|
||||
.noMatch(message.didNotFind("class").items(WEBJAR_ASSERT_LOCATOR));
|
||||
}
|
||||
return new ConditionOutcome(match,
|
||||
"Resource chain is " + (match ? "enabled" : "disabled"));
|
||||
if (match) {
|
||||
return ConditionOutcome.match(message.because("enabled"));
|
||||
}
|
||||
return ConditionOutcome.noMatch(message.because("disabled"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -216,9 +216,11 @@ public class ConditionEvaluationReportTests {
|
|||
for (ConditionAndOutcome outcome : outcomes) {
|
||||
messages.add(outcome.getOutcome().getMessage());
|
||||
}
|
||||
assertThat(messages).areAtLeastOne(Matched.by(
|
||||
containsString("@ConditionalOnClass classes found: javax.servlet.Servlet,"
|
||||
+ "org.springframework.web.multipart.support.StandardServletMultipartResolver")));
|
||||
assertThat(messages).areAtLeastOne(
|
||||
Matched.by(containsString("@ConditionalOnClass found required classes "
|
||||
+ "'javax.servlet.Servlet', 'org.springframework.web.multipart."
|
||||
+ "support.StandardServletMultipartResolver', "
|
||||
+ "'javax.servlet.MultipartConfigElement'")));
|
||||
context.close();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
* 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.condition;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage.Style;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link ConditionMessage}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class ConditionMessageTests {
|
||||
|
||||
@Test
|
||||
public void isEmptyWhenEmptyShouldReturnTrue() throws Exception {
|
||||
ConditionMessage message = ConditionMessage.empty();
|
||||
assertThat(message.isEmpty()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isEmptyWhenNotEmptyShouldReturnFalse() throws Exception {
|
||||
ConditionMessage message = ConditionMessage.of("Test");
|
||||
assertThat(message.isEmpty()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toStringWhenHasMessageShouldReturnMessage() throws Exception {
|
||||
ConditionMessage message = ConditionMessage.empty();
|
||||
assertThat(message.toString()).isEqualTo("");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toStringWhenEmptyShouldReturnEmptyString() throws Exception {
|
||||
ConditionMessage message = ConditionMessage.of("Test");
|
||||
assertThat(message.toString()).isEqualTo("Test");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void appendWhenHasExistingMessageShouldAddSpace() throws Exception {
|
||||
ConditionMessage message = ConditionMessage.of("a").append("b");
|
||||
assertThat(message.toString()).isEqualTo("a b");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void appendWhenAppendingNullShouldDoNothing() throws Exception {
|
||||
ConditionMessage message = ConditionMessage.of("a").append(null);
|
||||
assertThat(message.toString()).isEqualTo("a");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void appendWhenNoMessageShouldNotAddSpace() throws Exception {
|
||||
ConditionMessage message = ConditionMessage.empty().append("b");
|
||||
assertThat(message.toString()).isEqualTo("b");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void andConditionWhenUsingClassShouldIncludeCondition() throws Exception {
|
||||
ConditionMessage message = ConditionMessage.empty().andCondition(Test.class)
|
||||
.because("OK");
|
||||
assertThat(message.toString()).isEqualTo("@Test OK");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void andConditionWhenUsingStringShouldIncludeCondition() throws Exception {
|
||||
ConditionMessage message = ConditionMessage.empty().andCondition("@Test")
|
||||
.because("OK");
|
||||
assertThat(message.toString()).isEqualTo("@Test OK");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void andConditionWhenIncludingDetailsShouldIncludeCondition()
|
||||
throws Exception {
|
||||
ConditionMessage message = ConditionMessage.empty()
|
||||
.andCondition(Test.class, "(a=b)").because("OK");
|
||||
assertThat(message.toString()).isEqualTo("@Test (a=b) OK");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ofCollectionShouldCombine() throws Exception {
|
||||
List<ConditionMessage> messages = new ArrayList<ConditionMessage>();
|
||||
messages.add(ConditionMessage.of("a"));
|
||||
messages.add(ConditionMessage.of("b"));
|
||||
ConditionMessage message = ConditionMessage.of(messages);
|
||||
assertThat(message.toString()).isEqualTo("a; b");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ofCollectionWhenNullShouldReturnEmpty() throws Exception {
|
||||
ConditionMessage message = ConditionMessage.of((List<ConditionMessage>) null);
|
||||
assertThat(message.isEmpty()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forConditionShouldIncludeCondition() throws Exception {
|
||||
ConditionMessage message = ConditionMessage.forCondition("@Test").because("OK");
|
||||
assertThat(message.toString()).isEqualTo("@Test OK");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forConditionWhenClassShouldIncludeCondition() throws Exception {
|
||||
ConditionMessage message = ConditionMessage.forCondition(Test.class, "(a=b)")
|
||||
.because("OK");
|
||||
assertThat(message.toString()).isEqualTo("@Test (a=b) OK");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void foundExactlyShouldConstructMessage() throws Exception {
|
||||
ConditionMessage message = ConditionMessage.forCondition(Test.class)
|
||||
.foundExactly("abc");
|
||||
assertThat(message.toString()).isEqualTo("@Test found abc");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void foundWhenSingleElementShouldUsingSingular() throws Exception {
|
||||
ConditionMessage message = ConditionMessage.forCondition(Test.class)
|
||||
.found("bean", "beans").items("a");
|
||||
assertThat(message.toString()).isEqualTo("@Test found bean a");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void foundNoneAtAllShouldConstructMessage() throws Exception {
|
||||
ConditionMessage message = ConditionMessage.forCondition(Test.class)
|
||||
.found("no beans").atAll();
|
||||
assertThat(message.toString()).isEqualTo("@Test found no beans");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void foundWhenMultipleElementsShouldUsePlural() throws Exception {
|
||||
ConditionMessage message = ConditionMessage.forCondition(Test.class)
|
||||
.found("bean", "beans").items("a", "b", "c");
|
||||
assertThat(message.toString()).isEqualTo("@Test found beans a, b, c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void foundWhenQuoteStyleShouldQuote() throws Exception {
|
||||
ConditionMessage message = ConditionMessage.forCondition(Test.class)
|
||||
.found("bean", "beans").items(Style.QUOTE, "a", "b", "c");
|
||||
assertThat(message.toString()).isEqualTo("@Test found beans 'a', 'b', 'c'");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void didNotFindWhenSingleElementShouldUsingSingular() throws Exception {
|
||||
ConditionMessage message = ConditionMessage.forCondition(Test.class)
|
||||
.didNotFind("class", "classes").items("a");
|
||||
assertThat(message.toString()).isEqualTo("@Test did not find class a");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void didNotFindWhenMultipleElementsShouldUsePlural() throws Exception {
|
||||
ConditionMessage message = ConditionMessage.forCondition(Test.class)
|
||||
.didNotFind("class", "classes").items("a", "b", "c");
|
||||
assertThat(message.toString()).isEqualTo("@Test did not find classes a, b, c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resultedInShouldConstructMessage() throws Exception {
|
||||
ConditionMessage message = ConditionMessage.forCondition(Test.class)
|
||||
.resultedIn("Green");
|
||||
assertThat(message.toString()).isEqualTo("@Test resulted in Green");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void notAvailableShouldConstructMessage() throws Exception {
|
||||
ConditionMessage message = ConditionMessage.forCondition(Test.class)
|
||||
.notAvailable("JMX");
|
||||
assertThat(message.toString()).isEqualTo("@Test JMX is not available");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void availableShouldConstructMessage() throws Exception {
|
||||
ConditionMessage message = ConditionMessage.forCondition(Test.class)
|
||||
.available("JMX");
|
||||
assertThat(message.toString()).isEqualTo("@Test JMX is available");
|
||||
}
|
||||
|
||||
}
|
|
@ -70,37 +70,45 @@ public class ConditionalOnClassTests {
|
|||
@Configuration
|
||||
@ConditionalOnClass(ConditionalOnClassTests.class)
|
||||
protected static class BasicConfiguration {
|
||||
|
||||
@Bean
|
||||
public String bar() {
|
||||
return "bar";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(name = "FOO")
|
||||
protected static class MissingConfiguration {
|
||||
|
||||
@Bean
|
||||
public String bar() {
|
||||
return "bar";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
protected static class FooConfiguration {
|
||||
|
||||
@Bean
|
||||
public String foo() {
|
||||
return "foo";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ImportResource("org/springframework/boot/autoconfigure/condition/foo.xml")
|
||||
protected static class XmlConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import(BasicConfiguration.class)
|
||||
@ImportResource("org/springframework/boot/autoconfigure/condition/foo.xml")
|
||||
protected static class CombinedXmlConfiguration {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ public class ConditionalOnJavaTests {
|
|||
ConditionOutcome outcome = this.condition.getMatchOutcome(Range.EQUAL_OR_NEWER,
|
||||
JavaVersion.SEVEN, JavaVersion.SIX);
|
||||
assertThat(outcome.getMessage())
|
||||
.isEqualTo("Required JVM version " + "1.6 or newer found 1.7");
|
||||
.isEqualTo("@ConditionalOnJava (1.6 or newer) found 1.7");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -89,7 +89,7 @@ public class ConditionalOnJavaTests {
|
|||
ConditionOutcome outcome = this.condition.getMatchOutcome(Range.OLDER_THAN,
|
||||
JavaVersion.SEVEN, JavaVersion.SIX);
|
||||
assertThat(outcome.getMessage())
|
||||
.isEqualTo("Required JVM version " + "older than 1.6 found 1.7");
|
||||
.isEqualTo("@ConditionalOnJava (older than 1.6) found 1.7");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
|
|||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
|
@ -126,16 +127,18 @@ public class DevToolsDataSourceAutoConfiguration {
|
|||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
ConditionMessage.Builder message = ConditionMessage
|
||||
.forCondition("DevTools DataSource Condition");
|
||||
String[] dataSourceBeanNames = context.getBeanFactory()
|
||||
.getBeanNamesForType(DataSource.class);
|
||||
if (dataSourceBeanNames.length != 1) {
|
||||
return ConditionOutcome
|
||||
.noMatch("A single DataSource bean was not found in the context");
|
||||
.noMatch(message.didNotFind("a single DataSource bean").atAll());
|
||||
}
|
||||
if (context.getBeanFactory()
|
||||
.getBeanNamesForType(DataSourceProperties.class).length != 1) {
|
||||
return ConditionOutcome.noMatch(
|
||||
"A single DataSourceProperties bean was not found in the context");
|
||||
message.didNotFind("a single DataSourceProperties bean").atAll());
|
||||
}
|
||||
BeanDefinition dataSourceDefinition = context.getRegistry()
|
||||
.getBeanDefinition(dataSourceBeanNames[0]);
|
||||
|
@ -146,9 +149,11 @@ public class DevToolsDataSourceAutoConfiguration {
|
|||
.getFactoryMethodMetadata().getDeclaringClassName()
|
||||
.startsWith(DataSourceAutoConfiguration.class.getPackage()
|
||||
.getName() + ".DataSourceConfiguration$")) {
|
||||
return ConditionOutcome.match("Found auto-configured DataSource");
|
||||
return ConditionOutcome
|
||||
.match(message.foundExactly("auto-configured DataSource"));
|
||||
}
|
||||
return ConditionOutcome.noMatch("DataSource was not auto-configured");
|
||||
return ConditionOutcome
|
||||
.noMatch(message.didNotFind("an auto-configured DataSource").atAll());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
@ -18,6 +18,7 @@ package org.springframework.boot.devtools.remote.client;
|
|||
|
||||
import javax.net.ServerSocketFactory;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
||||
import org.springframework.boot.bind.RelaxedPropertyResolver;
|
||||
|
@ -35,6 +36,8 @@ class LocalDebugPortAvailableCondition extends SpringBootCondition {
|
|||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
ConditionMessage.Builder message = ConditionMessage
|
||||
.forCondition("Local Debug Port Condition");
|
||||
RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(
|
||||
context.getEnvironment(), "spring.devtools.remote.debug.");
|
||||
Integer port = resolver.getProperty("local-port", Integer.class);
|
||||
|
@ -42,9 +45,9 @@ class LocalDebugPortAvailableCondition extends SpringBootCondition {
|
|||
port = RemoteDevToolsProperties.Debug.DEFAULT_LOCAL_PORT;
|
||||
}
|
||||
if (isPortAvailable(port)) {
|
||||
return ConditionOutcome.match("Local debug port available");
|
||||
return ConditionOutcome.match(message.foundExactly("local debug port"));
|
||||
}
|
||||
return ConditionOutcome.noMatch("Local debug port unavailable");
|
||||
return ConditionOutcome.noMatch(message.didNotFind("local debug port").atAll());
|
||||
}
|
||||
|
||||
private boolean isPortAvailable(int port) {
|
||||
|
|
|
@ -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.
|
||||
|
@ -16,6 +16,7 @@
|
|||
|
||||
package org.springframework.boot.devtools.restart;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
|
@ -33,14 +34,16 @@ class OnInitializedRestarterCondition extends SpringBootCondition {
|
|||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
ConditionMessage.Builder message = ConditionMessage
|
||||
.forCondition("Initializer Restarter Condition");
|
||||
Restarter restarter = getRestarter();
|
||||
if (restarter == null) {
|
||||
return ConditionOutcome.noMatch("Restarter unavailable");
|
||||
return ConditionOutcome.noMatch(message.because("unavailable"));
|
||||
}
|
||||
if (restarter.getInitialUrls() == null) {
|
||||
return ConditionOutcome.noMatch("Restarter initialized without URLs");
|
||||
return ConditionOutcome.noMatch(message.because("initialized without URLs"));
|
||||
}
|
||||
return ConditionOutcome.match("Restarter available and initialized");
|
||||
return ConditionOutcome.match(message.because("available and initialized"));
|
||||
}
|
||||
|
||||
private Restarter getRestarter() {
|
||||
|
|
|
@ -47,7 +47,8 @@ public class LocalDebugPortAvailableConditionTests {
|
|||
public void portAvailable() throws Exception {
|
||||
ConditionOutcome outcome = getOutcome();
|
||||
assertThat(outcome.isMatch()).isTrue();
|
||||
assertThat(outcome.getMessage()).isEqualTo("Local debug port available");
|
||||
assertThat(outcome.getMessage())
|
||||
.isEqualTo("Local Debug Port Condition found local debug port");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -57,7 +58,8 @@ public class LocalDebugPortAvailableConditionTests {
|
|||
ConditionOutcome outcome = getOutcome();
|
||||
serverSocket.close();
|
||||
assertThat(outcome.isMatch()).isFalse();
|
||||
assertThat(outcome.getMessage()).isEqualTo("Local debug port unavailable");
|
||||
assertThat(outcome.getMessage())
|
||||
.isEqualTo("Local Debug Port Condition did not find local debug port");
|
||||
}
|
||||
|
||||
private ConditionOutcome getOutcome() {
|
||||
|
|
Loading…
Reference in New Issue