001/* 002 * Copyright 2012-2017 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.context.annotation.ConditionContext; 026import org.springframework.core.io.Resource; 027import org.springframework.core.type.AnnotatedTypeMetadata; 028 029/** 030 * {@link SpringBootCondition} used to check if a resource can be found using a 031 * configurable property and optional default location(s). 032 * 033 * @author Stephane Nicoll 034 * @author Phillip Webb 035 * @author Madhura Bhave 036 * @since 1.3.0 037 */ 038public abstract class ResourceCondition extends SpringBootCondition { 039 040 private final String name; 041 042 private final String property; 043 044 private final String[] resourceLocations; 045 046 /** 047 * Create a new condition. 048 * @param name the name of the component 049 * @param property the configuration property 050 * @param resourceLocations default location(s) where the configuration file can be 051 * found if the configuration key is not specified 052 * @since 2.0.0 053 */ 054 protected ResourceCondition(String name, String property, 055 String... resourceLocations) { 056 this.name = name; 057 this.property = property; 058 this.resourceLocations = resourceLocations; 059 } 060 061 @Override 062 public ConditionOutcome getMatchOutcome(ConditionContext context, 063 AnnotatedTypeMetadata metadata) { 064 if (context.getEnvironment().containsProperty(this.property)) { 065 return ConditionOutcome.match( 066 startConditionMessage().foundExactly("property " + this.property)); 067 } 068 return getResourceOutcome(context, metadata); 069 } 070 071 /** 072 * Check if one of the default resource locations actually exists. 073 * @param context the condition context 074 * @param metadata the annotation metadata 075 * @return the condition outcome 076 */ 077 protected ConditionOutcome getResourceOutcome(ConditionContext context, 078 AnnotatedTypeMetadata metadata) { 079 List<String> found = new ArrayList<>(); 080 for (String location : this.resourceLocations) { 081 Resource resource = context.getResourceLoader().getResource(location); 082 if (resource != null && resource.exists()) { 083 found.add(location); 084 } 085 } 086 if (found.isEmpty()) { 087 ConditionMessage message = startConditionMessage() 088 .didNotFind("resource", "resources") 089 .items(Style.QUOTE, Arrays.asList(this.resourceLocations)); 090 return ConditionOutcome.noMatch(message); 091 } 092 ConditionMessage message = startConditionMessage().found("resource", "resources") 093 .items(Style.QUOTE, found); 094 return ConditionOutcome.match(message); 095 } 096 097 protected final Builder startConditionMessage() { 098 return ConditionMessage.forCondition("ResourceCondition", "(" + this.name + ")"); 099 } 100 101}