001/* 002 * Copyright 2002-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 * https://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.core.env; 018 019import java.util.ArrayList; 020import java.util.Arrays; 021import java.util.Collection; 022import java.util.LinkedHashSet; 023import java.util.List; 024import java.util.Set; 025 026import org.springframework.util.StringUtils; 027 028/** 029 * Composite {@link PropertySource} implementation that iterates over a set of 030 * {@link PropertySource} instances. Necessary in cases where multiple property sources 031 * share the same name, e.g. when multiple values are supplied to {@code @PropertySource}. 032 * 033 * <p>As of Spring 4.1.2, this class extends {@link EnumerablePropertySource} instead 034 * of plain {@link PropertySource}, exposing {@link #getPropertyNames()} based on the 035 * accumulated property names from all contained sources (as far as possible). 036 * 037 * @author Chris Beams 038 * @author Juergen Hoeller 039 * @author Phillip Webb 040 * @since 3.1.1 041 */ 042public class CompositePropertySource extends EnumerablePropertySource<Object> { 043 044 private final Set<PropertySource<?>> propertySources = new LinkedHashSet<PropertySource<?>>(); 045 046 047 /** 048 * Create a new {@code CompositePropertySource}. 049 * @param name the name of the property source 050 */ 051 public CompositePropertySource(String name) { 052 super(name); 053 } 054 055 056 @Override 057 public Object getProperty(String name) { 058 for (PropertySource<?> propertySource : this.propertySources) { 059 Object candidate = propertySource.getProperty(name); 060 if (candidate != null) { 061 return candidate; 062 } 063 } 064 return null; 065 } 066 067 @Override 068 public boolean containsProperty(String name) { 069 for (PropertySource<?> propertySource : this.propertySources) { 070 if (propertySource.containsProperty(name)) { 071 return true; 072 } 073 } 074 return false; 075 } 076 077 @Override 078 public String[] getPropertyNames() { 079 Set<String> names = new LinkedHashSet<String>(); 080 for (PropertySource<?> propertySource : this.propertySources) { 081 if (!(propertySource instanceof EnumerablePropertySource)) { 082 throw new IllegalStateException( 083 "Failed to enumerate property names due to non-enumerable property source: " + propertySource); 084 } 085 names.addAll(Arrays.asList(((EnumerablePropertySource<?>) propertySource).getPropertyNames())); 086 } 087 return StringUtils.toStringArray(names); 088 } 089 090 091 /** 092 * Add the given {@link PropertySource} to the end of the chain. 093 * @param propertySource the PropertySource to add 094 */ 095 public void addPropertySource(PropertySource<?> propertySource) { 096 this.propertySources.add(propertySource); 097 } 098 099 /** 100 * Add the given {@link PropertySource} to the start of the chain. 101 * @param propertySource the PropertySource to add 102 * @since 4.1 103 */ 104 public void addFirstPropertySource(PropertySource<?> propertySource) { 105 List<PropertySource<?>> existing = new ArrayList<PropertySource<?>>(this.propertySources); 106 this.propertySources.clear(); 107 this.propertySources.add(propertySource); 108 this.propertySources.addAll(existing); 109 } 110 111 /** 112 * Return all property sources that this composite source holds. 113 * @since 4.1.1 114 */ 115 public Collection<PropertySource<?>> getPropertySources() { 116 return this.propertySources; 117 } 118 119 120 @Override 121 public String toString() { 122 return String.format("%s [name='%s', propertySources=%s]", 123 getClass().getSimpleName(), this.name, this.propertySources); 124 } 125 126}