3cab8aa0fbf8443c18c578aeeac34a218d714f47
[ccsdk/oran.git] /
1 /*-
2  * ========================LICENSE_START=================================
3  * ONAP : ccsdk oran
4  * ======================================================================
5  * Copyright (C) 2019-2020 Nordix Foundation. All rights reserved.
6  * ======================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ========================LICENSE_END===================================
19  */
20
21 package org.onap.ccsdk.oran.a1policymanagementservice.configuration;
22
23 import com.google.gson.JsonArray;
24 import com.google.gson.JsonElement;
25 import com.google.gson.JsonObject;
26
27 import java.io.File;
28 import java.io.IOException;
29 import java.net.URL;
30 import java.nio.file.Files;
31 import java.util.ArrayList;
32 import java.util.Arrays;
33 import java.util.HashMap;
34 import java.util.HashSet;
35 import java.util.Iterator;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.Map.Entry;
39 import java.util.Set;
40
41 import javax.validation.constraints.NotNull;
42
43 import org.immutables.gson.Gson;
44 import org.immutables.value.Value;
45 import org.json.JSONObject;
46 import org.onap.ccsdk.oran.a1policymanagementservice.exceptions.ServiceException;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
49
50 /**
51  * Parser for the Json representing of the component configuration.
52  */
53 public class ApplicationConfigParser {
54     private static final Logger logger = LoggerFactory.getLogger(ApplicationConfigParser.class);
55
56     private static final String CONFIG = "config";
57     private static final String CONTROLLER = "controller";
58     private final ApplicationConfig applicationConfig;
59
60     public ApplicationConfigParser(ApplicationConfig applicationConfig) {
61         this.applicationConfig = applicationConfig;
62     }
63
64     @Value.Immutable
65     @Gson.TypeAdapters
66     public interface ConfigParserResult {
67         List<RicConfig> ricConfigs();
68
69         Map<String, ControllerConfig> controllerConfigs();
70
71         String dmaapConsumerTopicUrl();
72
73         String dmaapProducerTopicUrl();
74
75     }
76
77     public ConfigParserResult parse(JsonObject root) throws ServiceException {
78
79         validateJsonObjectAgainstSchema(root);
80
81         String dmaapProducerTopicUrl = "";
82         String dmaapConsumerTopicUrl = "";
83
84         JsonObject pmsConfigJson = root.getAsJsonObject(CONFIG);
85
86         if (pmsConfigJson == null) {
87             throw new ServiceException("Missing root configuration \"" + CONFIG + "\" in JSON: " + root);
88         }
89
90         JsonObject json = pmsConfigJson.getAsJsonObject("streams_publishes");
91         if (json != null) {
92             dmaapProducerTopicUrl = parseDmaapConfig(json);
93         }
94
95         json = pmsConfigJson.getAsJsonObject("streams_subscribes");
96         if (json != null) {
97             dmaapConsumerTopicUrl = parseDmaapConfig(json);
98         }
99
100         List<RicConfig> ricConfigs = parseRics(pmsConfigJson);
101         Map<String, ControllerConfig> controllerConfigs = parseControllerConfigs(pmsConfigJson);
102         checkConfigurationConsistency(ricConfigs, controllerConfigs);
103
104         return ImmutableConfigParserResult.builder() //
105                 .dmaapConsumerTopicUrl(dmaapConsumerTopicUrl) //
106                 .dmaapProducerTopicUrl(dmaapProducerTopicUrl) //
107                 .ricConfigs(ricConfigs) //
108                 .controllerConfigs(controllerConfigs) //
109                 .build();
110     }
111
112     private void validateJsonObjectAgainstSchema(Object object) throws ServiceException {
113         if (applicationConfig.getConfigurationFileSchemaPath() == null
114                 || applicationConfig.getConfigurationFileSchemaPath().isEmpty()) {
115             return;
116         }
117
118         try {
119             String schemaAsString = readSchemaFile();
120
121             JSONObject schemaJSON = new JSONObject(schemaAsString);
122             var schema = org.everit.json.schema.loader.SchemaLoader.load(schemaJSON);
123
124             String objectAsString = object.toString();
125             JSONObject json = new JSONObject(objectAsString);
126             schema.validate(json);
127         } catch (Exception e) {
128             throw new ServiceException("Json schema validation failure: " + e.toString());
129         }
130     }
131
132     private String readSchemaFile() throws IOException {
133         ClassLoader classLoader = getClass().getClassLoader();
134         String filePath = applicationConfig.getConfigurationFileSchemaPath();
135         URL url = classLoader.getResource(filePath);
136         File file = new File(url.getFile());
137         return new String(Files.readAllBytes(file.toPath()));
138
139     }
140
141     private void checkConfigurationConsistency(List<RicConfig> ricConfigs,
142             Map<String, ControllerConfig> controllerConfigs) throws ServiceException {
143         Set<String> ricUrls = new HashSet<>();
144         Set<String> ricNames = new HashSet<>();
145         for (RicConfig ric : ricConfigs) {
146             if (!ricUrls.add(ric.baseUrl())) {
147                 throw new ServiceException("Configuration error, more than one RIC URL: " + ric.baseUrl());
148             }
149             if (!ricNames.add(ric.ricId())) {
150                 throw new ServiceException("Configuration error, more than one RIC with name: " + ric.ricId());
151             }
152             if (!ric.controllerName().isEmpty() && controllerConfigs.get(ric.controllerName()) == null) {
153                 throw new ServiceException(
154                         "Configuration error, controller configuration not found: " + ric.controllerName());
155             }
156         }
157     }
158
159     private List<RicConfig> parseRics(JsonObject config) throws ServiceException {
160         List<RicConfig> result = new ArrayList<>();
161         for (JsonElement ricElem : getAsJsonArray(config, "ric")) {
162             JsonObject ricAsJson = ricElem.getAsJsonObject();
163             JsonElement controllerNameElement = ricAsJson.get(CONTROLLER);
164             RicConfig ricConfig = ImmutableRicConfig.builder() //
165                     .ricId(get(ricAsJson, "name", "id", "ricId").getAsString()) //
166                     .baseUrl(get(ricAsJson, "baseUrl").getAsString()) //
167                     .managedElementIds(parseManagedElementIds(get(ricAsJson, "managedElementIds").getAsJsonArray())) //
168                     .controllerName(controllerNameElement != null ? controllerNameElement.getAsString() : "") //
169                     .build();
170             if (!ricConfig.baseUrl().isEmpty()) {
171                 result.add(ricConfig);
172             } else {
173                 logger.error("RIC configuration error {}, baseUrl is empty", ricConfig.ricId());
174             }
175         }
176         return result;
177     }
178
179     Map<String, ControllerConfig> parseControllerConfigs(JsonObject config) throws ServiceException {
180         if (config.get(CONTROLLER) == null) {
181             return new HashMap<>();
182         }
183         Map<String, ControllerConfig> result = new HashMap<>();
184         for (JsonElement element : getAsJsonArray(config, CONTROLLER)) {
185             JsonObject controllerAsJson = element.getAsJsonObject();
186             ImmutableControllerConfig controllerConfig = ImmutableControllerConfig.builder() //
187                     .name(get(controllerAsJson, "name").getAsString()) //
188                     .baseUrl(get(controllerAsJson, "baseUrl").getAsString()) //
189                     .password(get(controllerAsJson, "password").getAsString()) //
190                     .userName(get(controllerAsJson, "userName").getAsString()) // )
191                     .build();
192
193             if (result.put(controllerConfig.name(), controllerConfig) != null) {
194                 throw new ServiceException(
195                         "Configuration error, more than one controller with name: " + controllerConfig.name());
196             }
197         }
198         return result;
199     }
200
201     private List<String> parseManagedElementIds(JsonArray asJsonObject) {
202         Iterator<JsonElement> iterator = asJsonObject.iterator();
203         List<String> managedElementIds = new ArrayList<>();
204         while (iterator.hasNext()) {
205             managedElementIds.add(iterator.next().getAsString());
206
207         }
208         return managedElementIds;
209     }
210
211     private static JsonElement get(JsonObject obj, String... alternativeMemberNames) throws ServiceException {
212         for (String memberName : alternativeMemberNames) {
213             JsonElement elem = obj.get(memberName);
214             if (elem != null) {
215                 return elem;
216             }
217         }
218         throw new ServiceException("Could not find member: " + Arrays.toString(alternativeMemberNames) + " in: " + obj);
219     }
220
221     private JsonArray getAsJsonArray(JsonObject obj, String memberName) throws ServiceException {
222         return get(obj, memberName).getAsJsonArray();
223     }
224
225     private String parseDmaapConfig(JsonObject streamCfg) throws ServiceException {
226         Set<Entry<String, JsonElement>> streamConfigEntries = streamCfg.entrySet();
227         if (streamConfigEntries.size() != 1) {
228             throw new ServiceException(
229                     "Invalid configuration. Number of streams must be one, config: " + streamConfigEntries);
230         }
231         JsonObject streamConfigEntry = streamConfigEntries.iterator().next().getValue().getAsJsonObject();
232         JsonObject dmaapInfo = get(streamConfigEntry, "dmaap_info").getAsJsonObject();
233         return getAsString(dmaapInfo, "topic_url");
234     }
235
236     private static @NotNull String getAsString(JsonObject obj, String memberName) throws ServiceException {
237         return get(obj, memberName).getAsString();
238     }
239 }