/* * Copyright 2012-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.boot.actuate.endpoint; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonPropertyOrder; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.endpoint.AutoConfigurationReportEndpoint.Report; import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport; import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport.ConditionAndOutcome; import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport.ConditionAndOutcomes; import org.springframework.boot.autoconfigure.condition.ConditionOutcome; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Condition; import org.springframework.util.ClassUtils; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.util.StringUtils; /** * {@link Endpoint} to expose the {@link ConditionEvaluationReport}. * * @author Greg Turnquist * @author Phillip Webb * @author Dave Syer * @author Andy Wilkinson */ @ConfigurationProperties(prefix = "endpoints.autoconfig") public class AutoConfigurationReportEndpoint extends AbstractEndpoint<Report> { @Autowired private ConditionEvaluationReport autoConfigurationReport; public AutoConfigurationReportEndpoint() { super("autoconfig"); } @Override public Report invoke() { return new Report(this.autoConfigurationReport); } /** * Adapts {@link ConditionEvaluationReport} to a JSON friendly structure. */ @JsonPropertyOrder({ "positiveMatches", "negativeMatches", "exclusions" }) @JsonInclude(Include.NON_EMPTY) public static class Report { private final MultiValueMap<String, MessageAndCondition> positiveMatches; private final Map<String, MessageAndConditions> negativeMatches; private final List<String> exclusions; private final Report parent; public Report(ConditionEvaluationReport report) { this.positiveMatches = new LinkedMultiValueMap<>(); this.negativeMatches = new LinkedHashMap<>(); this.exclusions = report.getExclusions(); for (Map.Entry<String, ConditionAndOutcomes> entry : report .getConditionAndOutcomesBySource().entrySet()) { if (entry.getValue().isFullMatch()) { add(this.positiveMatches, entry.getKey(), entry.getValue()); } else { add(this.negativeMatches, entry.getKey(), entry.getValue()); } } boolean hasParent = report.getParent() != null; this.parent = (hasParent ? new Report(report.getParent()) : null); } private void add(Map<String, MessageAndConditions> map, String source, ConditionAndOutcomes conditionAndOutcomes) { String name = ClassUtils.getShortName(source); map.put(name, new MessageAndConditions(conditionAndOutcomes)); } private void add(MultiValueMap<String, MessageAndCondition> map, String source, ConditionAndOutcomes conditionAndOutcomes) { String name = ClassUtils.getShortName(source); for (ConditionAndOutcome conditionAndOutcome : conditionAndOutcomes) { map.add(name, new MessageAndCondition(conditionAndOutcome)); } } public Map<String, List<MessageAndCondition>> getPositiveMatches() { return this.positiveMatches; } public Map<String, MessageAndConditions> getNegativeMatches() { return this.negativeMatches; } public List<String> getExclusions() { return this.exclusions; } public Report getParent() { return this.parent; } } /** * Adapts {@link ConditionAndOutcomes} to a JSON friendly structure. */ @JsonPropertyOrder({ "notMatched", "matched" }) public static class MessageAndConditions { private final List<MessageAndCondition> notMatched = new ArrayList<>(); private final List<MessageAndCondition> matched = new ArrayList<>(); public MessageAndConditions(ConditionAndOutcomes conditionAndOutcomes) { for (ConditionAndOutcome conditionAndOutcome : conditionAndOutcomes) { List<MessageAndCondition> target = conditionAndOutcome.getOutcome() .isMatch() ? this.matched : this.notMatched; target.add(new MessageAndCondition(conditionAndOutcome)); } } public List<MessageAndCondition> getNotMatched() { return this.notMatched; } public List<MessageAndCondition> getMatched() { return this.matched; } } /** * Adapts {@link ConditionAndOutcome} to a JSON friendly structure. */ @JsonPropertyOrder({ "condition", "message" }) public static class MessageAndCondition { private final String condition; private final String message; public MessageAndCondition(ConditionAndOutcome conditionAndOutcome) { Condition condition = conditionAndOutcome.getCondition(); ConditionOutcome outcome = conditionAndOutcome.getOutcome(); this.condition = ClassUtils.getShortName(condition.getClass()); if (StringUtils.hasLength(outcome.getMessage())) { this.message = outcome.getMessage(); } else { this.message = (outcome.isMatch() ? "matched" : "did not match"); } } public String getCondition() { return this.condition; } public String getMessage() { return this.message; } } }