207312747cb01799a296d2fc1dca903c41ef4485
[dcaegen2/analytics/tca-gen2.git] / dcae-analytics / dcae-analytics-web / src / main / java / org / onap / dcae / analytics / web / spring / ConfigBindingServiceEnvironmentPostProcessor.java
1 /*
2  * ================================================================================
3  * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
4  * ================================================================================
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  * ============LICENSE_END=========================================================
17  *
18  */
19
20 package org.onap.dcae.analytics.web.spring;
21
22 import java.util.Arrays;
23 import java.util.Collections;
24 import java.util.Map;
25 import java.util.Optional;
26 import java.util.Set;
27 import java.util.stream.Collectors;
28
29 import org.onap.dcae.analytics.model.AnalyticsProfile;
30 import org.onap.dcae.analytics.model.configbindingservice.ConfigBindingServiceConstants;
31 import org.onap.dcae.analytics.model.util.function.JsonStringToMapFunction;
32 import org.onap.dcae.analytics.model.util.supplier.ConfigBindingServiceJsonSupplier;
33 import org.onap.dcae.analytics.web.exception.AnalyticsValidationException;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36 import org.springframework.boot.SpringApplication;
37 import org.springframework.boot.env.EnvironmentPostProcessor;
38 import org.springframework.core.Ordered;
39 import org.springframework.core.env.ConfigurableEnvironment;
40 import org.springframework.core.env.MapPropertySource;
41 import org.springframework.core.env.MutablePropertySources;
42 import org.springframework.core.env.PropertySource;
43 import org.springframework.core.env.StandardEnvironment;
44 import org.springframework.util.ClassUtils;
45 import org.springframework.web.context.support.StandardServletEnvironment;
46
47 /**
48  * A custom spring framework environment post processor which can fetch and populate spring context with
49  * Config Binding Service application properties.
50  * <p>
51  * Activated only when config binding service profile is active.
52  *
53  * @author Rajiv Singla
54  */
55 public class ConfigBindingServiceEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {
56
57     private static final Logger logger = LoggerFactory.getLogger(ConfigBindingServiceEnvironmentPostProcessor.class);
58     private static final String SERVLET_ENVIRONMENT_CLASS =
59             "org.springframework.web.context.support.StandardServletEnvironment";
60
61     private static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE;
62
63     @Override
64     public void postProcessEnvironment(final ConfigurableEnvironment environment, final SpringApplication application) {
65
66         final boolean isConfigServiceProfilePresent = Arrays.stream(environment.getActiveProfiles())
67                 .anyMatch(p -> p.equalsIgnoreCase(AnalyticsProfile.CONFIG_BINDING_SERVICE_PROFILE_NAME));
68
69         if (!isConfigServiceProfilePresent) {
70             logger.info("Config Binding Service Profile is not active. " +
71                     "Skipping Adding config binding service properties");
72             return;
73         }
74
75         logger.info("Config Binding Service Profile is active. " +
76                 "Application properties will be fetched from config binding service");
77
78         // Fetch config binding service json
79         final Optional<String> configServiceJsonOptional = new ConfigBindingServiceJsonSupplier().get();
80
81         if (!configServiceJsonOptional.isPresent()) {
82             final String errorMessage = "Unable to get fetch application configuration from config binding service";
83             throw new AnalyticsValidationException(errorMessage, new IllegalStateException(errorMessage));
84         }
85
86         final String configServicePropertiesKey = ConfigBindingServiceConstants.CONFIG_BINDING_SERVICE_PROPERTIES_KEY;
87
88         // convert fetch config binding service json string to Map of property key and values
89         final Map<String, Object> configPropertiesMap = configServiceJsonOptional
90                 .map(new JsonStringToMapFunction(configServicePropertiesKey))
91                 .orElse(Collections.emptyMap());
92
93         if (configPropertiesMap.isEmpty()) {
94
95             logger.warn("No properties found in config binding service");
96
97         } else {
98
99             // remove config service key prefix on spring reserved property key prefixes
100             final Set<String> springKeyPrefixes = ConfigBindingServiceConstants.SPRING_RESERVED_PROPERTIES_KEY_PREFIXES;
101             final Set<String> springKeys = springKeyPrefixes.stream()
102                     .map(springKeyPrefix -> configServicePropertiesKey + "." + springKeyPrefix)
103                     .collect(Collectors.toSet());
104
105             final Map<String, Object> filterKeyMap = configPropertiesMap.entrySet()
106                     .stream()
107                     .collect(Collectors.toMap(
108                             (Map.Entry<String, Object> e) ->
109                                     springKeys.stream().anyMatch(springKey -> e.getKey().startsWith(springKey)) ?
110                                             e.getKey().substring(configServicePropertiesKey.toCharArray().length + 1) :
111                                             e.getKey(),
112                             Map.Entry::getValue)
113                     );
114
115             filterKeyMap.forEach((key, value) ->
116                     logger.info("Adding property from config service in spring context: {} -> {}", key, value));
117
118             addJsonPropertySource(environment, new MapPropertySource(configServicePropertiesKey, filterKeyMap));
119         }
120
121     }
122
123     @Override
124     public int getOrder() {
125         return DEFAULT_ORDER;
126     }
127
128
129     private void addJsonPropertySource(final ConfigurableEnvironment environment, final PropertySource<?> source) {
130         final MutablePropertySources sources = environment.getPropertySources();
131         final String name = findPropertySource(sources);
132         if (sources.contains(name)) {
133             sources.addBefore(name, source);
134         } else {
135             sources.addFirst(source);
136         }
137     }
138
139     private String findPropertySource(final MutablePropertySources sources) {
140         if (ClassUtils.isPresent(SERVLET_ENVIRONMENT_CLASS, null) &&
141                 sources.contains(StandardServletEnvironment.JNDI_PROPERTY_SOURCE_NAME)) {
142             return StandardServletEnvironment.JNDI_PROPERTY_SOURCE_NAME;
143
144         }
145         return StandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME;
146     }
147
148 }