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.configurationmetadata;
018
019import java.io.Serializable;
020import java.util.Collection;
021import java.util.Collections;
022import java.util.HashMap;
023import java.util.Map;
024
025/**
026 * The default {@link ConfigurationMetadataRepository} implementation.
027 *
028 * @author Stephane Nicoll
029 * @since 1.3.0
030 */
031@SuppressWarnings("serial")
032public class SimpleConfigurationMetadataRepository
033                implements ConfigurationMetadataRepository, Serializable {
034
035        private final Map<String, ConfigurationMetadataGroup> allGroups = new HashMap<>();
036
037        @Override
038        public Map<String, ConfigurationMetadataGroup> getAllGroups() {
039                return Collections.unmodifiableMap(this.allGroups);
040        }
041
042        @Override
043        public Map<String, ConfigurationMetadataProperty> getAllProperties() {
044                Map<String, ConfigurationMetadataProperty> properties = new HashMap<>();
045                for (ConfigurationMetadataGroup group : this.allGroups.values()) {
046                        properties.putAll(group.getProperties());
047                }
048                return properties;
049        }
050
051        /**
052         * Register the specified {@link ConfigurationMetadataSource sources}.
053         * @param sources the sources to add
054         */
055        public void add(Collection<ConfigurationMetadataSource> sources) {
056                for (ConfigurationMetadataSource source : sources) {
057                        String groupId = source.getGroupId();
058                        ConfigurationMetadataGroup group = this.allGroups.get(groupId);
059                        if (group == null) {
060                                group = new ConfigurationMetadataGroup(groupId);
061                                this.allGroups.put(groupId, group);
062                        }
063                        String sourceType = source.getType();
064                        if (sourceType != null) {
065                                putIfAbsent(group.getSources(), sourceType, source);
066                        }
067                }
068        }
069
070        /**
071         * Add a {@link ConfigurationMetadataProperty} with the
072         * {@link ConfigurationMetadataSource source} that defines it, if any.
073         * @param property the property to add
074         * @param source the source
075         */
076        public void add(ConfigurationMetadataProperty property,
077                        ConfigurationMetadataSource source) {
078                if (source != null) {
079                        putIfAbsent(source.getProperties(), property.getId(), property);
080                }
081                putIfAbsent(getGroup(source).getProperties(), property.getId(), property);
082        }
083
084        /**
085         * Merge the content of the specified repository to this repository.
086         * @param repository the repository to include
087         */
088        public void include(ConfigurationMetadataRepository repository) {
089                for (ConfigurationMetadataGroup group : repository.getAllGroups().values()) {
090                        ConfigurationMetadataGroup existingGroup = this.allGroups.get(group.getId());
091                        if (existingGroup == null) {
092                                this.allGroups.put(group.getId(), group);
093                        }
094                        else {
095                                // Merge properties
096                                group.getProperties().forEach((name, value) -> putIfAbsent(
097                                                existingGroup.getProperties(), name, value));
098                                // Merge sources
099                                group.getSources().forEach((name,
100                                                value) -> putIfAbsent(existingGroup.getSources(), name, value));
101                        }
102                }
103
104        }
105
106        private ConfigurationMetadataGroup getGroup(ConfigurationMetadataSource source) {
107                if (source == null) {
108                        ConfigurationMetadataGroup rootGroup = this.allGroups.get(ROOT_GROUP);
109                        if (rootGroup == null) {
110                                rootGroup = new ConfigurationMetadataGroup(ROOT_GROUP);
111                                this.allGroups.put(ROOT_GROUP, rootGroup);
112                        }
113                        return rootGroup;
114                }
115                return this.allGroups.get(source.getGroupId());
116        }
117
118        private <V> void putIfAbsent(Map<String, V> map, String key, V value) {
119                if (!map.containsKey(key)) {
120                        map.put(key, value);
121                }
122        }
123
124}