001/* 002 * Copyright 2012-2016 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.boot.autoconfigure.condition; 018 019import java.util.ArrayList; 020import java.util.Arrays; 021import java.util.List; 022 023import org.springframework.boot.autoconfigure.condition.ConditionMessage.Builder; 024import org.springframework.boot.autoconfigure.condition.ConditionMessage.Style; 025import org.springframework.boot.bind.RelaxedPropertyResolver; 026import org.springframework.context.annotation.ConditionContext; 027import org.springframework.core.io.Resource; 028import org.springframework.core.type.AnnotatedTypeMetadata; 029 030/** 031 * {@link SpringBootCondition} used to check if a resource can be found using a 032 * configurable property and optional default location(s). 033 * 034 * @author Stephane Nicoll 035 * @author Phillip Webb 036 * @since 1.3.0 037 */ 038public abstract class ResourceCondition extends SpringBootCondition { 039 040 private final String name; 041 042 private final String prefix; 043 044 private final String propertyName; 045 046 private final String[] resourceLocations; 047 048 /** 049 * Create a new condition. 050 * @param name the name of the component 051 * @param prefix the prefix of the configuration key 052 * @param propertyName the name of the configuration key 053 * @param resourceLocations default location(s) where the configuration file can be 054 * found if the configuration key is not specified 055 */ 056 protected ResourceCondition(String name, String prefix, String propertyName, 057 String... resourceLocations) { 058 this.name = name; 059 this.prefix = (prefix.endsWith(".") ? prefix : prefix + "."); 060 this.propertyName = propertyName; 061 this.resourceLocations = resourceLocations; 062 } 063 064 @Override 065 public ConditionOutcome getMatchOutcome(ConditionContext context, 066 AnnotatedTypeMetadata metadata) { 067 RelaxedPropertyResolver resolver = new RelaxedPropertyResolver( 068 context.getEnvironment(), this.prefix); 069 if (resolver.containsProperty(this.propertyName)) { 070 return ConditionOutcome.match(startConditionMessage() 071 .foundExactly("property " + this.prefix + this.propertyName)); 072 } 073 return getResourceOutcome(context, metadata); 074 } 075 076 /** 077 * Check if one of the default resource locations actually exists. 078 * @param context the condition context 079 * @param metadata the annotation metadata 080 * @return the condition outcome 081 */ 082 protected ConditionOutcome getResourceOutcome(ConditionContext context, 083 AnnotatedTypeMetadata metadata) { 084 List<String> found = new ArrayList<String>(); 085 for (String location : this.resourceLocations) { 086 Resource resource = context.getResourceLoader().getResource(location); 087 if (resource != null && resource.exists()) { 088 found.add(location); 089 } 090 } 091 if (found.isEmpty()) { 092 ConditionMessage message = startConditionMessage() 093 .didNotFind("resource", "resources") 094 .items(Style.QUOTE, Arrays.asList(this.resourceLocations)); 095 return ConditionOutcome.noMatch(message); 096 } 097 ConditionMessage message = startConditionMessage().found("resource", "resources") 098 .items(Style.QUOTE, found); 099 return ConditionOutcome.match(message); 100 } 101 102 protected final Builder startConditionMessage() { 103 return ConditionMessage.forCondition("ResourceCondition", "(" + this.name + ")"); 104 } 105 106}