2 * Copyright 2017 Huawei Technologies Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package org.onap.cli.fw.http.schema;
19 import java.io.IOException;
20 import java.util.ArrayList;
21 import java.util.HashMap;
22 import java.util.HashSet;
23 import java.util.List;
25 import java.util.Map.Entry;
27 import java.util.stream.Collectors;
29 import org.onap.cli.fw.cmd.OnapCommand;
30 import org.onap.cli.fw.cmd.OnapCommandType;
31 import org.onap.cli.fw.conf.OnapCommandConfig;
32 import org.onap.cli.fw.conf.OnapCommandConstants;
33 import org.onap.cli.fw.error.OnapCommandException;
34 import org.onap.cli.fw.error.OnapCommandInvalidSchema;
35 import org.onap.cli.fw.error.OnapCommandNotFound;
36 import org.onap.cli.fw.http.auth.OnapCommandHttpService;
37 import org.onap.cli.fw.http.cmd.OnapHttpCommand;
38 import org.onap.cli.fw.http.conf.OnapCommandHttpConstants;
39 import org.onap.cli.fw.http.error.OnapCommandHttpInvalidResultMap;
40 import org.onap.cli.fw.registrar.OnapCommandRegistrar;
41 import org.onap.cli.fw.schema.OnapCommandSchemaLoader;
42 import org.onap.cli.fw.utils.OnapCommandUtils;
44 import com.fasterxml.jackson.databind.ObjectMapper;
46 import net.minidev.json.JSONObject;
48 public class OnapCommandSchemaHttpLoader {
50 public static List<String> loadHttpSchema(OnapHttpCommand cmd, String schemaName, boolean includeDefault,
51 boolean validateSchema) throws OnapCommandException {
53 List<String> errors = new ArrayList<>();
55 Map<String, ?> defaultParameterMap = OnapCommandSchemaLoader.validateSchemaVersion(OnapCommandHttpConstants.DEFAULT_PARAMETER_HTTP_FILE_NAME, cmd.getSchemaVersion());
57 //mrkanag default_parameter is supported only for parameters.
58 if (defaultParameterMap.containsKey(OnapCommandConstants.INFO)) {
59 defaultParameterMap.remove(OnapCommandConstants.INFO);
62 errors.addAll(OnapCommandSchemaLoader.parseSchema(cmd, defaultParameterMap, validateSchema));
65 Map<String, List<Map<String, String>>> commandYamlMap =
66 (Map<String, List<Map<String, String>>>)OnapCommandSchemaLoader.validateSchemaVersion(schemaName, cmd.getSchemaVersion());
68 errors.addAll(parseHttpSchema(cmd, commandYamlMap, validateSchema));
72 } catch (OnapCommandException e) {
74 } catch (Exception e) {
75 throw new OnapCommandInvalidSchema(schemaName, e);
86 * @throws OnapCommandException
89 public static ArrayList<String> parseHttpSchema(OnapHttpCommand cmd,
90 final Map<String, ?> values,
91 boolean validate) throws OnapCommandException {
92 ArrayList<String> errorList = new ArrayList<>();
94 Map<String, ?> valMap = (Map<String, ?>) values.get(OnapCommandHttpConstants.HTTP);
98 OnapCommandUtils.validateTags(errorList, valMap, OnapCommandConfig.getCommaSeparatedList(OnapCommandHttpConstants.HTTP_SECTIONS),
99 OnapCommandConfig.getCommaSeparatedList(OnapCommandHttpConstants.HTTP_MANDATORY_SECTIONS), OnapCommandHttpConstants.HTTP);
100 errorList.addAll(validateHttpSchemaSection(values));
102 for (Map.Entry<String, ?> entry1 : valMap.entrySet()) {
103 String key1 = entry1.getKey();
106 case OnapCommandHttpConstants.REQUEST:
107 Map<String, ?> map = (Map<String, ?>) valMap.get(key1);
109 for (Map.Entry<String, ?> entry2 : map.entrySet()) {
111 String key2 = entry2.getKey();
114 case OnapCommandHttpConstants.URI:
115 Object obj = map.get(key2);
116 cmd.getInput().setUri(obj.toString());
118 case OnapCommandHttpConstants.METHOD_TYPE:
119 Object method = map.get(key2);
120 cmd.getInput().setMethod(method.toString());
122 case OnapCommandHttpConstants.BODY:
123 Object body = map.get(key2);
124 cmd.getInput().setBody(body.toString());
126 case OnapCommandHttpConstants.HEADERS:
127 Map<String, String> head = (Map<String, String>) map.get(key2);
128 cmd.getInput().setReqHeaders(head);
130 case OnapCommandHttpConstants.QUERIES:
131 Map<String, String> query = (Map<String, String>) map.get(key2);
133 cmd.getInput().setReqQueries(query);
135 case OnapCommandHttpConstants.CONTEXT:
136 Map<String, Object> context = (Map<String, Object>) map.get(key2);
138 for (String key: context.keySet()) {
140 case OnapCommandHttpConstants.CONTEXT_REMOVE_EMPTY_JSON_NODES:
141 Boolean flag = (Boolean) context.get(OnapCommandHttpConstants.CONTEXT_REMOVE_EMPTY_JSON_NODES);
142 cmd.getInput().getContext().put(OnapCommandHttpConstants.CONTEXT_REMOVE_EMPTY_JSON_NODES, flag.toString());
149 case OnapCommandHttpConstants.MULTIPART_ENTITY_NAME:
150 Object multipartEntityName = map.get(key2);
151 cmd.getInput().setMultipartEntityName(multipartEntityName.toString());
154 }catch (Exception ex) {
155 OnapCommandUtils.throwOrCollect(new OnapCommandInvalidSchema(cmd.getSchemaName(), ex), errorList, validate);
160 case OnapCommandHttpConstants.SERVICE:
161 Map<String, String> serviceMap = (Map<String, String>) valMap.get(key1);
163 if (serviceMap != null) {
165 OnapCommandUtils.validateTags(errorList, (Map<String, Object>) valMap.get(key1),
166 OnapCommandConfig.getCommaSeparatedList(OnapCommandHttpConstants.SERVICE_PARAMS_LIST),
167 OnapCommandConfig.getCommaSeparatedList(OnapCommandHttpConstants.SERVICE_PARAMS_MANDATORY_LIST), OnapCommandHttpConstants.SERVICE);
169 HashMap<String, String> validationMap = new HashMap<>();
170 validationMap.put(OnapCommandHttpConstants.AUTH, OnapCommandHttpConstants.AUTH_VALUES);
171 validationMap.put(OnapCommandHttpConstants.MODE, OnapCommandHttpConstants.MODE_VALUES);
173 for (String secKey : validationMap.keySet()) {
174 if (serviceMap.containsKey(secKey)) {
175 Object obj = serviceMap.get(secKey);
177 errorList.add("Attribute '" + secKey + "' under '" + OnapCommandHttpConstants.SERVICE + "' is empty");
179 String value = String.valueOf(obj);
180 if (!OnapCommandConfig.getCommaSeparatedList(validationMap.get(secKey)).contains(value)) {
181 errorList.add("Attribute '" + secKey + "' contains invalid value. Valide values are "
182 + OnapCommandConfig.getCommaSeparatedList(validationMap.get(key1))); //
189 OnapCommandHttpService srv = new OnapCommandHttpService();
191 for (Map.Entry<String, String> entry : serviceMap.entrySet()) {
192 String key = entry.getKey();
195 case OnapCommandConstants.NAME:
196 srv.setName(serviceMap.get(key));
199 case OnapCommandHttpConstants.VERSION:
200 srv.setVersion(serviceMap.get(key).toString());
203 case OnapCommandHttpConstants.AUTH:
204 Object obj = serviceMap.get(key);
205 srv.setAuthType(obj.toString());
208 case OnapCommandHttpConstants.MODE:
209 Object mode = serviceMap.get(key);
210 srv.setMode(mode.toString());
219 case OnapCommandHttpConstants.SUCCESS_CODES:
221 validateHttpSccessCodes(errorList, (List<Object>) valMap.get(key1));
223 cmd.setSuccessStatusCodes((ArrayList) valMap.get(key1));
226 case OnapCommandHttpConstants.RESULT_MAP:
228 validateHttpResultMap(errorList, values);
230 cmd.setResultMap((Map<String, String>) valMap.get(key1));
233 case OnapCommandHttpConstants.SAMPLE_RESPONSE:
234 // (mrkanag) implement sample response handling
239 }catch (OnapCommandException e) {
240 OnapCommandUtils.throwOrCollect(e, errorList, validate);
243 //Handle the parameters for auth:
244 // for commands, copy params from login command to this command
245 if (!cmd.getService().isNoAuth()) {
246 if (cmd.getInfo().getCommandType().equals(OnapCommandType.AUTH)) {
247 OnapCommandUtils.throwOrCollect(new OnapCommandInvalidSchema(
248 cmd.getSchemaName(), "For auth type commands, http->service->auth should be none"),
252 OnapCommand login = OnapCommandSchemaHttpLoader.findAuthCommand(cmd, "login");
253 OnapCommandUtils.copyParamSchemasFrom(login, cmd);
256 //with service->auth: none,
257 //normal cmd: ignore all auth parms
258 if (!cmd.getInfo().getCommandType().equals(OnapCommandType.AUTH)) {
259 cmd.getParametersMap().get(OnapCommandHttpConstants.DEAFULT_PARAMETER_USERNAME).setInclude(false);
260 cmd.getParametersMap().get(OnapCommandHttpConstants.DEAFULT_PARAMETER_PASSWORD).setInclude(false);
261 cmd.getParametersMap().get(OnapCommandHttpConstants.DEFAULT_PARAMETER_NO_AUTH).setInclude(false);
263 //auth: login and logout commands, ignore no-auth
264 cmd.getParametersMap().get(OnapCommandHttpConstants.DEFAULT_PARAMETER_NO_AUTH).setInclude(false);
265 //auth: only for logout commands, ignore username and password too
266 if (!cmd.getName().endsWith(OnapCommandHttpConstants.AUTH_SERVICE_LOGIN)) {
267 cmd.getParametersMap().get(OnapCommandHttpConstants.DEAFULT_PARAMETER_USERNAME).setInclude(false);
268 cmd.getParametersMap().get(OnapCommandHttpConstants.DEAFULT_PARAMETER_PASSWORD).setInclude(false);
276 public static ArrayList<String> validateHttpSchemaSection(Map<String, ?> values) {
277 ArrayList<String> errorList = new ArrayList<>();
278 Map<String, ?> map = (Map<String, ?>) values.get(OnapCommandHttpConstants.HTTP);
279 Map<String, Object> requestMap = (Map<String, Object>) map.get(OnapCommandHttpConstants.REQUEST);
281 if (requestMap != null && !requestMap.isEmpty()) {
282 OnapCommandUtils.validateTags(errorList, requestMap, OnapCommandConfig.getCommaSeparatedList(OnapCommandHttpConstants.HTTP_REQUEST_PARAMS),
283 OnapCommandConfig.getCommaSeparatedList(OnapCommandHttpConstants.HTTP_REQUEST_MANDATORY_PARAMS), OnapCommandHttpConstants.REQUEST);
284 String method = (String) requestMap.get(OnapCommandHttpConstants.METHOD);
285 if (method != null && !method.isEmpty()) {
286 if (!OnapCommandConfig.getCommaSeparatedList(OnapCommandHttpConstants.HTTP_METHODS).contains(method.toLowerCase())) {
287 errorList.add("Attribute '" + OnapCommandHttpConstants.METHOD + "' under '" + OnapCommandHttpConstants.REQUEST + "' is invalid, correct types are "
288 + OnapCommandConfig.getCommaSeparatedList(OnapCommandHttpConstants.HTTP_METHODS).toString());
291 errorList.add("Http request method cann't be null or empty");
294 Set<String> requestParams = getRequestParams(values);
296 Set<String> uriParams = validateHttpUri(errorList, requestMap);
298 Set<String> bodyParams = validateHttpBody(errorList, requestMap);
300 Set<String> headerParams = validateHttpHeaders(requestMap);
302 Set<String> queryParams = validateHttpQueries(requestMap);
304 HashSet<String> totoalParams = new HashSet<>(uriParams);
305 totoalParams.addAll(bodyParams);
306 totoalParams.addAll(headerParams);
307 totoalParams.addAll(queryParams);
309 List<String> nonDeclaredParams = totoalParams.stream().filter(param -> !requestParams.contains(param))
310 .collect(Collectors.toList());
312 nonDeclaredParams.stream().forEach(p -> errorList.add("The parameter '" + p
313 + "' declared under 'parameters:' section is not mapped into request section."));
315 errorList.add(OnapCommandUtils.emptySection(OnapCommandHttpConstants.REQUEST));
320 public static void validateHttpSccessCodes(List<String> errorList, List<Object> requestSuccessCodes) {
322 if (requestSuccessCodes == null || requestSuccessCodes.isEmpty()) {
323 errorList.add(OnapCommandHttpConstants.HTTP_SUCCESS_CODE_INVALID);
327 for (Object successCode : requestSuccessCodes) {
328 Integer code = (Integer) successCode;
329 if (code < 200 || code >= 300) {
331 errorList.add(OnapCommandHttpConstants.HTTP_SUCCESS_CODE_INVALID);
338 public static void validateHttpResultMap(List<String> errorList, Map<String, ?> values) throws OnapCommandException {
339 Map<String, ?> valMap = (Map<String, ?>) values.get(OnapCommandHttpConstants.HTTP);
340 List<Map<String, String>> attributes = (List<Map<String, String>>) ((Map<String, ?>)values.get(OnapCommandConstants.RESULTS)).get(OnapCommandConstants.ATTRIBUTES);
341 Set<String> resultMapParams = ((Map<String, String>) valMap.get(OnapCommandHttpConstants.RESULT_MAP)).keySet();
343 Set<String> resultAttNames = attributes.stream().map(map -> map.get(OnapCommandConstants.NAME))
344 .collect(Collectors.toSet());
346 List<String> invaliResultMapParams = resultMapParams.stream()
347 .filter(p -> !resultAttNames.contains(p)).collect(Collectors.toList());
348 List<String> attributesMissing = resultAttNames.stream()
349 .filter(p -> !resultMapParams.contains(p)).collect(Collectors.toList());
350 invaliResultMapParams.addAll(attributesMissing);
352 if (!invaliResultMapParams.isEmpty()) {
353 OnapCommandUtils.throwOrCollect(new OnapCommandHttpInvalidResultMap(invaliResultMapParams), errorList, true);
357 public static Set<String> validateHttpQueries(Map<String, Object> requestMap) {
358 Map<String, Object> queries = (Map<String, Object>) requestMap.get(OnapCommandHttpConstants.QUERIES);
359 Set<String> queryParamNames = new HashSet<>();
360 if (queries != null) {
361 for (Entry<String, Object> entry : queries.entrySet()) {
362 OnapCommandUtils.parseParameters(String.valueOf(entry.getValue()), queryParamNames);
365 return queryParamNames;
368 public static Set<String> validateHttpHeaders(Map<String, Object> requestMap) {
370 Map<String, Object> headers = (Map<String, Object>) requestMap.get(OnapCommandHttpConstants.HEADERS);
371 Set<String> headerParamNames = new HashSet<>();
372 if (headers != null) {
373 for (Entry<String, Object> entry : headers.entrySet()) {
374 OnapCommandUtils.parseParameters(String.valueOf(entry.getValue()), headerParamNames);
377 return headerParamNames;
380 public static Set<String> validateHttpBody(List<String> errorList, Map<String, Object> requestMap) {
381 Set<String> bodyParamNames = new HashSet<>();
382 Object bodyString = requestMap.get(OnapCommandHttpConstants.BODY);
383 if (bodyString == null) {
384 return bodyParamNames;
387 String body = String.valueOf(bodyString);
389 if (body == null || "".equals(body)) {
390 errorList.add(OnapCommandHttpConstants.HTTP_BODY_JSON_EMPTY);
393 new ObjectMapper().readValue(body, JSONObject.class);
394 } catch (IOException e1) { // NOSONAR
395 errorList.add(OnapCommandHttpConstants.HTTP_BODY_FAILED_PARSING);
399 OnapCommandUtils.parseParameters(body, bodyParamNames);
401 return bodyParamNames;
404 public static Set<String> validateHttpUri(List<String> errorList, Map<String, Object> requestMap) {
405 Set<String> uriParamNames = new HashSet<>();
406 String uri = (String) requestMap.get(OnapCommandHttpConstants.URI);
407 if (uri == null || uri.isEmpty()) {
408 errorList.add(OnapCommandUtils.emptySection(OnapCommandHttpConstants.URI));
409 return uriParamNames;
411 OnapCommandUtils.parseParameters(uri, uriParamNames);
412 return uriParamNames;
415 public static Set<String> getRequestParams(Map<String, ?> yamlMap) {
417 Set<String> set = new HashSet<>();
419 @SuppressWarnings("unchecked")
420 List<Map<String, Object>> inputParams = (List<Map<String, Object>>) yamlMap.get(OnapCommandConstants.PARAMETERS);
422 if (inputParams != null) {
423 for (Map<String, Object> map : inputParams) {
424 for (Entry<String, Object> entry : map.entrySet()) {
425 Object key = entry.getKey();
427 if (OnapCommandConstants.NAME.equals(key)) {
428 set.add(String.valueOf(entry.getValue()));
440 * @param authAction login/logout
442 * @throws OnapCommandException
444 public static OnapCommand findAuthCommand(OnapHttpCommand forCmd, String authAction) throws OnapCommandException {
445 OnapCommand auth = null;
447 //mrkanag: fix this to discover the auth command by matching info->product & service
448 auth = OnapCommandRegistrar.getRegistrar().get(
449 forCmd.getInfo().getService() + "-" +
450 forCmd.getService().getAuthType() + "-" + authAction,
451 forCmd.getInfo().getProduct());
452 } catch (OnapCommandNotFound e) { // NOSONAR
453 auth = OnapCommandRegistrar.getRegistrar().get(
454 forCmd.getService().getAuthType() + "-" + authAction,
455 forCmd.getInfo().getProduct());