001/*
002 * Copyright 2012-2018 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.context.properties.bind;
018
019import org.springframework.core.env.ConfigurableEnvironment;
020import org.springframework.core.env.Environment;
021import org.springframework.core.env.PropertySource;
022import org.springframework.core.env.PropertySources;
023import org.springframework.util.Assert;
024import org.springframework.util.PropertyPlaceholderHelper;
025import org.springframework.util.SystemPropertyUtils;
026
027/**
028 * {@link PlaceholdersResolver} to resolve placeholders from {@link PropertySources}.
029 *
030 * @author Phillip Webb
031 * @author Madhura Bhave
032 * @since 2.0.0
033 */
034public class PropertySourcesPlaceholdersResolver implements PlaceholdersResolver {
035
036        private final Iterable<PropertySource<?>> sources;
037
038        private final PropertyPlaceholderHelper helper;
039
040        public PropertySourcesPlaceholdersResolver(Environment environment) {
041                this(getSources(environment), null);
042        }
043
044        public PropertySourcesPlaceholdersResolver(Iterable<PropertySource<?>> sources) {
045                this(sources, null);
046        }
047
048        public PropertySourcesPlaceholdersResolver(Iterable<PropertySource<?>> sources,
049                        PropertyPlaceholderHelper helper) {
050                this.sources = sources;
051                this.helper = (helper != null) ? helper
052                                : new PropertyPlaceholderHelper(SystemPropertyUtils.PLACEHOLDER_PREFIX,
053                                                SystemPropertyUtils.PLACEHOLDER_SUFFIX,
054                                                SystemPropertyUtils.VALUE_SEPARATOR, true);
055        }
056
057        @Override
058        public Object resolvePlaceholders(Object value) {
059                if (value != null && value instanceof String) {
060                        return this.helper.replacePlaceholders((String) value,
061                                        this::resolvePlaceholder);
062                }
063                return value;
064        }
065
066        protected String resolvePlaceholder(String placeholder) {
067                if (this.sources != null) {
068                        for (PropertySource<?> source : this.sources) {
069                                Object value = source.getProperty(placeholder);
070                                if (value != null) {
071                                        return String.valueOf(value);
072                                }
073                        }
074                }
075                return null;
076        }
077
078        private static PropertySources getSources(Environment environment) {
079                Assert.notNull(environment, "Environment must not be null");
080                Assert.isInstanceOf(ConfigurableEnvironment.class, environment,
081                                "Environment must be a ConfigurableEnvironment");
082                return ((ConfigurableEnvironment) environment).getPropertySources();
083        }
084
085}