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.actuate.info;
018
019import java.util.Collections;
020import java.util.LinkedHashMap;
021import java.util.Map;
022import java.util.Properties;
023
024import org.springframework.boot.context.properties.bind.Bindable;
025import org.springframework.boot.context.properties.bind.Binder;
026import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
027import org.springframework.boot.info.InfoProperties;
028import org.springframework.core.env.PropertySource;
029import org.springframework.util.StringUtils;
030
031/**
032 * A base {@link InfoContributor} to expose an {@link InfoProperties}.
033 *
034 * @param <T> the type of the {@link InfoProperties} to expose
035 * @author Stephane Nicoll
036 * @author Madhura Bhave
037 * @since 1.4.0
038 */
039public abstract class InfoPropertiesInfoContributor<T extends InfoProperties>
040                implements InfoContributor {
041
042        private static final Bindable<Map<String, Object>> STRING_OBJECT_MAP = Bindable
043                        .mapOf(String.class, Object.class);
044
045        private final T properties;
046
047        private final Mode mode;
048
049        protected InfoPropertiesInfoContributor(T properties, Mode mode) {
050                this.properties = properties;
051                this.mode = mode;
052        }
053
054        /**
055         * Return the properties that this instance manages.
056         * @return the info properties
057         */
058        protected final T getProperties() {
059                return this.properties;
060        }
061
062        /**
063         * Return the mode that should be used to expose the content.
064         * @return the mode
065         */
066        protected final Mode getMode() {
067                return this.mode;
068        }
069
070        /**
071         * Return a {@link PropertySource} for the {@link Mode#SIMPLE SIMPLE} mode.
072         * @return the property source for the simple model
073         * @see #toPropertySource()
074         */
075        protected abstract PropertySource<?> toSimplePropertySource();
076
077        /**
078         * Extract the content to contribute to the info endpoint.
079         * @return the content to expose
080         * @see #extractContent(PropertySource)
081         * @see #postProcessContent(Map)
082         */
083        protected Map<String, Object> generateContent() {
084                Map<String, Object> content = extractContent(toPropertySource());
085                postProcessContent(content);
086                return content;
087        }
088
089        /**
090         * Extract the raw content based on the specified {@link PropertySource}.
091         * @param propertySource the property source to use
092         * @return the raw content
093         */
094        protected Map<String, Object> extractContent(PropertySource<?> propertySource) {
095                return new Binder(ConfigurationPropertySources.from(propertySource))
096                                .bind("", STRING_OBJECT_MAP).orElseGet(LinkedHashMap::new);
097        }
098
099        /**
100         * Post-process the content to expose. Elements can be added, changed or removed.
101         * @param content the content to expose
102         */
103        protected void postProcessContent(Map<String, Object> content) {
104
105        }
106
107        /**
108         * Return the {@link PropertySource} to use based on the chosen {@link Mode}.
109         * @return the property source
110         */
111        protected PropertySource<?> toPropertySource() {
112                if (this.mode.equals(Mode.FULL)) {
113                        return this.properties.toPropertySource();
114                }
115                return toSimplePropertySource();
116        }
117
118        /**
119         * Copy the specified key to the target {@link Properties} if it is set.
120         * @param target the target properties to update
121         * @param key the key
122         */
123        protected void copyIfSet(Properties target, String key) {
124                String value = this.properties.get(key);
125                if (StringUtils.hasText(value)) {
126                        target.put(key, value);
127                }
128        }
129
130        /**
131         * Replace the {@code value} for the specified key if the value is not {@code null}.
132         * @param content the content to expose
133         * @param key the property to replace
134         * @param value the new value
135         */
136        protected void replaceValue(Map<String, Object> content, String key, Object value) {
137                if (content.containsKey(key) && value != null) {
138                        content.put(key, value);
139                }
140        }
141
142        /**
143         * Return the nested map with the specified key or empty map if the specified map
144         * contains no mapping for the key.
145         * @param map the content
146         * @param key the key of a nested map
147         * @return the nested map
148         */
149        @SuppressWarnings("unchecked")
150        protected Map<String, Object> getNestedMap(Map<String, Object> map, String key) {
151                Object value = map.get(key);
152                if (value == null) {
153                        return Collections.emptyMap();
154                }
155                return (Map<String, Object>) value;
156        }
157
158        /**
159         * Defines how properties should be exposed.
160         */
161        public enum Mode {
162
163                /**
164                 * Expose all available data, including custom properties.
165                 */
166                FULL,
167
168                /**
169                 * Expose a pre-defined set of core settings only.
170                 */
171                SIMPLE
172
173        }
174
175}