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.util.ArrayList;
20 import java.util.HashMap;
21 import java.util.HashSet;
22 import java.util.List;
24 import java.util.Map.Entry;
26 import java.util.stream.Collectors;
28 import org.onap.cli.fw.cmd.OnapCommand;
29 import org.onap.cli.fw.cmd.OnapCommandType;
30 import org.onap.cli.fw.conf.OnapCommandConfig;
31 import org.onap.cli.fw.conf.OnapCommandConstants;
32 import org.onap.cli.fw.error.OnapCommandException;
33 import org.onap.cli.fw.error.OnapCommandInvalidSchema;
34 import org.onap.cli.fw.error.OnapCommandNotFound;
35 import org.onap.cli.fw.http.auth.OnapCommandHttpService;
36 import org.onap.cli.fw.http.cmd.OnapHttpCommand;
37 import org.onap.cli.fw.http.conf.OnapCommandHttpConstants;
38 import org.onap.cli.fw.http.connect.HttpInput;
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.google.gson.Gson;
45 import com.google.gson.GsonBuilder;
46 import com.google.gson.JsonElement;
48 public class OnapCommandSchemaHttpLoader {
50 private static final String ATTRIBUTE = "Attribute '";
51 private static Gson gson = new GsonBuilder().serializeNulls().create();
53 private OnapCommandSchemaHttpLoader() {
54 // to follow standards !
57 public static List<String> loadHttpSchema(OnapHttpCommand cmd, String schemaName, boolean includeDefault, boolean validateSchema) throws OnapCommandException {
59 List<String> errors = new ArrayList<>();
61 Map<String, ?> defaultParameterMap = OnapCommandSchemaLoader.validateSchemaVersion(OnapCommandHttpConstants.DEFAULT_PARAMETER_HTTP_FILE_NAME, cmd.getSchemaVersion());
63 //mrkanag default_parameter is supported only for parameters.
64 if (defaultParameterMap.containsKey(OnapCommandConstants.INFO)) {
65 defaultParameterMap.remove(OnapCommandConstants.INFO);
68 errors.addAll(OnapCommandSchemaLoader.parseSchema(cmd, defaultParameterMap, validateSchema));
71 Map<String, ?> commandYamlMap =
72 OnapCommandSchemaLoader.validateSchemaVersion(schemaName, cmd.getSchemaVersion());
74 errors.addAll(parseHttpSchema(cmd, commandYamlMap, validateSchema));
78 } catch (OnapCommandException e) {
80 } catch (Exception e) {
81 throw new OnapCommandInvalidSchema(schemaName, e);
92 * @throws OnapCommandException
95 public static List<String> parseHttpSchema(OnapHttpCommand cmd,
96 final Map<String, ?> values,
97 boolean validate) throws OnapCommandException {
98 ArrayList<String> errorList = new ArrayList<>();
100 Map<String, ?> valMap = (Map<String, ?>) values.get(OnapCommandHttpConstants.HTTP);
102 if (valMap != null) {
104 OnapCommandUtils.validateTags(errorList, valMap, OnapCommandConfig.getCommaSeparatedList(OnapCommandHttpConstants.HTTP_SECTIONS),
105 OnapCommandConfig.getCommaSeparatedList(OnapCommandHttpConstants.HTTP_MANDATORY_SECTIONS), OnapCommandHttpConstants.HTTP);
106 errorList.addAll(validateHttpSchemaSection(values));
108 for (Map.Entry<String, ?> entry1 : valMap.entrySet()) {
109 String key1 = entry1.getKey();
112 case OnapCommandHttpConstants.REQUEST:
113 Map<String, ?> map = (Map<String, ?>) valMap.get(key1);
115 for (Map.Entry<String, ?> entry2 : map.entrySet()) {
117 String key2 = entry2.getKey();
120 case OnapCommandHttpConstants.URI:
121 Object obj = map.get(key2);
122 cmd.getInput().setUri(obj.toString());
124 case OnapCommandHttpConstants.METHOD_TYPE:
125 Object method = map.get(key2);
126 cmd.getInput().setMethod(method.toString());
128 case OnapCommandHttpConstants.BODY:
129 Object body = map.get(key2);
131 if (body instanceof String) {
132 cmd.getInput().setBody(body.toString());
134 //check for multipart
135 Map <String, Object> multipartBody = (Map<String, Object>) body;
136 List <Object> multiparts = (List<Object>) multipartBody.get(OnapCommandHttpConstants.MULTIPART);
138 for (Object part: multiparts ) {
139 HttpInput.Part partO = new HttpInput.Part();
140 Map<String, String> partMap = (Map<String, String>) part;
141 partO.setName(partMap.get("name"));
142 partO.setContent(partMap.get("content"));
143 if (partMap.get("type") != null && (partMap.get("type")).equalsIgnoreCase("file")) {
144 partO.setBinary(true);
147 cmd.getInput().getMultiparts().add(partO);
152 case OnapCommandHttpConstants.HEADERS:
153 Map<String, String> head = (Map<String, String>) map.get(key2);
154 cmd.getInput().setReqHeaders(head);
156 case OnapCommandHttpConstants.QUERIES:
157 Map<String, String> query = (Map<String, String>) map.get(key2);
159 cmd.getInput().setReqQueries(query);
161 case OnapCommandHttpConstants.CONTEXT:
162 Map<String, Object> context = (Map<String, Object>) map.get(key2);
164 for (String key: context.keySet()) {
165 if (OnapCommandHttpConstants.CONTEXT_REMOVE_EMPTY_JSON_NODES.equals(key)) {
166 Boolean flag = Boolean.valueOf(context.get(OnapCommandHttpConstants.CONTEXT_REMOVE_EMPTY_JSON_NODES).toString());
167 cmd.getInput().getContext().put(OnapCommandHttpConstants.CONTEXT_REMOVE_EMPTY_JSON_NODES, flag.toString());
172 case OnapCommandHttpConstants.MULTIPART_ENTITY_NAME:
173 Object multipartEntityName = map.get(key2);
174 cmd.getInput().setMultipartEntityName(multipartEntityName.toString());
176 default : // Do nothing
178 }catch (Exception ex) {
179 OnapCommandUtils.throwOrCollect(new OnapCommandInvalidSchema(cmd.getSchemaName(), ex), errorList, validate);
184 case OnapCommandHttpConstants.SERVICE:
185 Map<String, String> serviceMap = (Map<String, String>) valMap.get(key1);
187 if (serviceMap != null) {
189 OnapCommandUtils.validateTags(errorList, (Map<String, Object>) valMap.get(key1),
190 OnapCommandConfig.getCommaSeparatedList(OnapCommandHttpConstants.SERVICE_PARAMS_LIST),
191 OnapCommandConfig.getCommaSeparatedList(OnapCommandHttpConstants.SERVICE_PARAMS_MANDATORY_LIST), OnapCommandHttpConstants.SERVICE);
193 HashMap<String, String> validationMap = new HashMap<>();
194 validationMap.put(OnapCommandHttpConstants.AUTH, OnapCommandHttpConstants.AUTH_VALUES);
195 validationMap.put(OnapCommandHttpConstants.MODE, OnapCommandHttpConstants.MODE_VALUES);
197 for (Map.Entry<String, String> secKey : validationMap.entrySet()) {
198 if (serviceMap.containsKey(secKey.getKey())) {
199 Object obj = serviceMap.get(secKey.getKey());
201 errorList.add(ATTRIBUTE + secKey.getKey() + "' under '" + OnapCommandHttpConstants.SERVICE + "' is empty");
203 String value = String.valueOf(obj);
204 if (!OnapCommandConfig.getCommaSeparatedList(validationMap.get(secKey.getKey())).contains(value)) {
205 errorList.add(ATTRIBUTE + secKey.getKey() + "' contains invalid value. Valide values are "
206 + OnapCommandConfig.getCommaSeparatedList(validationMap.get(key1))); //
213 OnapCommandHttpService srv = new OnapCommandHttpService();
215 for (Map.Entry<String, String> entry : serviceMap.entrySet()) {
216 String key = entry.getKey();
219 case OnapCommandConstants.NAME:
220 srv.setName(serviceMap.get(key));
223 case OnapCommandHttpConstants.VERSION:
224 srv.setVersion(serviceMap.get(key));
227 case OnapCommandHttpConstants.AUTH:
228 Object obj = serviceMap.get(key);
229 srv.setAuthType(obj.toString());
232 case OnapCommandHttpConstants.MODE:
233 Object mode = serviceMap.get(key);
234 srv.setMode(mode.toString());
236 default : // Do nothing
244 case OnapCommandHttpConstants.SUCCESS_CODES:
246 validateHttpSccessCodes(errorList, (List<Object>) valMap.get(key1));
248 List<String> list = (ArrayList) valMap.get(key1);
249 cmd.setSuccessStatusCodes(list.stream().map(Integer::parseInt).collect(Collectors.toList()));
252 case OnapCommandHttpConstants.RESULT_MAP:
254 validateHttpResultMap(errorList, values);
256 cmd.setResultMap((Map<String, String>) valMap.get(key1));
259 case OnapCommandHttpConstants.SAMPLE_RESPONSE:
260 // (mrkanag) implement sample response handling
262 default : // Do nothing
266 }catch (OnapCommandException e) {
267 OnapCommandUtils.throwOrCollect(e, errorList, validate);
270 //Handle the parameters for auth:
271 // for commands, copy params from login command to this command
272 if (!cmd.getService().isNoAuth()) {
273 if (cmd.getInfo().getCommandType().equals(OnapCommandType.AUTH)) {
274 OnapCommandUtils.throwOrCollect(new OnapCommandInvalidSchema(
275 cmd.getSchemaName(), "For auth type commands, http->service->auth should be none"),
279 OnapCommand login = OnapCommandSchemaHttpLoader.findAuthCommand(cmd, "login");
280 OnapCommandUtils.copyParamSchemasFrom(login, cmd);
283 //with service->auth: none,
284 //normal cmd: ignore all auth parms
285 if (!cmd.getInfo().getCommandType().equals(OnapCommandType.AUTH)) {
286 cmd.getParametersMap().get(OnapCommandHttpConstants.DEAFULT_PARAMETER_USERNAME).setInclude(false);
287 cmd.getParametersMap().get(OnapCommandHttpConstants.DEAFULT_PARAMETER_PASSWORD).setInclude(false);
288 cmd.getParametersMap().get(OnapCommandHttpConstants.DEFAULT_PARAMETER_NO_AUTH).setInclude(false);
290 //auth: login and logout commands, ignore no-auth
291 cmd.getParametersMap().get(OnapCommandHttpConstants.DEFAULT_PARAMETER_NO_AUTH).setInclude(false);
292 //auth: only for logout commands, ignore username and password too
293 if (!cmd.getName().endsWith(OnapCommandHttpConstants.AUTH_SERVICE_LOGIN)) {
294 cmd.getParametersMap().get(OnapCommandHttpConstants.DEAFULT_PARAMETER_USERNAME).setInclude(false);
295 cmd.getParametersMap().get(OnapCommandHttpConstants.DEAFULT_PARAMETER_PASSWORD).setInclude(false);
303 public static List<String> validateHttpSchemaSection(Map<String, ?> values) {
304 ArrayList<String> errorList = new ArrayList<>();
305 Map<String, ?> map = (Map<String, ?>) values.get(OnapCommandHttpConstants.HTTP);
306 Map<String, Object> requestMap = (Map<String, Object>) map.get(OnapCommandHttpConstants.REQUEST);
308 if (requestMap != null && !requestMap.isEmpty()) {
309 OnapCommandUtils.validateTags(errorList, requestMap, OnapCommandConfig.getCommaSeparatedList(OnapCommandHttpConstants.HTTP_REQUEST_PARAMS),
310 OnapCommandConfig.getCommaSeparatedList(OnapCommandHttpConstants.HTTP_REQUEST_MANDATORY_PARAMS), OnapCommandHttpConstants.REQUEST);
311 String method = (String) requestMap.get(OnapCommandHttpConstants.METHOD);
312 if (method != null && !method.isEmpty()) {
313 if (!OnapCommandConfig.getCommaSeparatedList(OnapCommandHttpConstants.HTTP_METHODS).contains(method.toLowerCase())) {
314 errorList.add(ATTRIBUTE + OnapCommandHttpConstants.METHOD + "' under '" + OnapCommandHttpConstants.REQUEST + "' is invalid, correct types are "
315 + OnapCommandConfig.getCommaSeparatedList(OnapCommandHttpConstants.HTTP_METHODS).toString());
318 errorList.add("Http request method cann't be null or empty");
321 Set<String> requestParams = getRequestParams(values);
323 Set<String> uriParams = validateHttpUri(errorList, requestMap);
325 Set<String> bodyParams = validateHttpBody(errorList, requestMap);
327 Set<String> headerParams = validateHttpHeaders(requestMap);
329 Set<String> queryParams = validateHttpQueries(requestMap);
331 HashSet<String> totoalParams = new HashSet<>(uriParams);
332 totoalParams.addAll(bodyParams);
333 totoalParams.addAll(headerParams);
334 totoalParams.addAll(queryParams);
336 List<String> nonDeclaredParams = totoalParams.stream().filter(param -> !requestParams.contains(param))
337 .collect(Collectors.toList());
339 nonDeclaredParams.stream().forEach(p -> errorList.add("The parameter '" + p
340 + "' declared under 'parameters:' section is not mapped into request section."));
342 errorList.add(OnapCommandUtils.emptySection(OnapCommandHttpConstants.REQUEST));
347 public static void validateHttpSccessCodes(List<String> errorList, List<Object> requestSuccessCodes) {
349 if (requestSuccessCodes == null || requestSuccessCodes.isEmpty()) {
350 errorList.add(OnapCommandHttpConstants.HTTP_SUCCESS_CODE_INVALID);
354 for (Object successCode : requestSuccessCodes) {
355 Integer code = Integer.valueOf(String.valueOf(successCode));
356 if ((code < 200 || code >= 300) && code != 404) {
357 errorList.add(OnapCommandHttpConstants.HTTP_SUCCESS_CODE_INVALID);
363 public static void validateHttpResultMap(List<String> errorList, Map<String, ?> values) throws OnapCommandException {
364 Map<String, ?> valMap = (Map<String, ?>) values.get(OnapCommandHttpConstants.HTTP);
365 List<Map<String, String>> attributes = (List<Map<String, String>>) ((Map<String, ?>)values.get(OnapCommandConstants.RESULTS)).get(OnapCommandConstants.ATTRIBUTES);
366 Set<String> resultMapParams = ((Map<String, String>) valMap.get(OnapCommandHttpConstants.RESULT_MAP)).keySet();
368 Set<String> resultAttNames = attributes.stream().map(map -> map.get(OnapCommandConstants.NAME))
369 .collect(Collectors.toSet());
371 List<String> invaliResultMapParams = resultMapParams.stream()
372 .filter(p -> !resultAttNames.contains(p)).collect(Collectors.toList());
373 List<String> attributesMissing = resultAttNames.stream()
374 .filter(p -> !resultMapParams.contains(p)).collect(Collectors.toList());
375 invaliResultMapParams.addAll(attributesMissing);
377 if (!invaliResultMapParams.isEmpty()) {
378 OnapCommandUtils.throwOrCollect(new OnapCommandHttpInvalidResultMap(invaliResultMapParams), errorList, true);
382 public static Set<String> validateHttpQueries(Map<String, Object> requestMap) {
383 Map<String, Object> queries = (Map<String, Object>) requestMap.get(OnapCommandHttpConstants.QUERIES);
384 Set<String> queryParamNames = new HashSet<>();
385 if (queries != null) {
386 for (Entry<String, Object> entry : queries.entrySet()) {
387 OnapCommandUtils.parseParameters(String.valueOf(entry.getValue()), queryParamNames);
390 return queryParamNames;
393 public static Set<String> validateHttpHeaders(Map<String, Object> requestMap) {
395 Map<String, Object> headers = (Map<String, Object>) requestMap.get(OnapCommandHttpConstants.HEADERS);
396 Set<String> headerParamNames = new HashSet<>();
397 if (headers != null) {
398 for (Entry<String, Object> entry : headers.entrySet()) {
399 OnapCommandUtils.parseParameters(String.valueOf(entry.getValue()), headerParamNames);
402 return headerParamNames;
405 public static Set<String> validateHttpBody(List<String> errorList, Map<String, Object> requestMap) {
406 Set<String> bodyParamNames = new HashSet<>();
407 Object bodyString = requestMap.get(OnapCommandHttpConstants.BODY);
408 if (bodyString == null) {
409 return bodyParamNames;
412 String body = String.valueOf(bodyString);
414 if (body == null || "".equals(body)) {
415 errorList.add(OnapCommandHttpConstants.HTTP_BODY_JSON_EMPTY);
418 gson.fromJson(body, JsonElement.class);
419 } catch (Exception e1) { // NOSONAR
420 errorList.add(OnapCommandHttpConstants.HTTP_BODY_FAILED_PARSING);
424 OnapCommandUtils.parseParameters(body, bodyParamNames);
426 return bodyParamNames;
429 public static Set<String> validateHttpUri(List<String> errorList, Map<String, Object> requestMap) {
430 Set<String> uriParamNames = new HashSet<>();
431 String uri = (String) requestMap.get(OnapCommandHttpConstants.URI);
432 if (uri == null || uri.isEmpty()) {
433 errorList.add(OnapCommandUtils.emptySection(OnapCommandHttpConstants.URI));
434 return uriParamNames;
436 OnapCommandUtils.parseParameters(uri, uriParamNames);
437 return uriParamNames;
440 public static Set<String> getRequestParams(Map<String, ?> yamlMap) {
442 Set<String> set = new HashSet<>();
444 @SuppressWarnings("unchecked")
445 List<Map<String, Object>> inputParams = (List<Map<String, Object>>) yamlMap.get(OnapCommandConstants.PARAMETERS);
447 if (inputParams != null) {
448 for (Map<String, Object> map : inputParams) {
449 for (Entry<String, Object> entry : map.entrySet()) {
450 Object key = entry.getKey();
452 if (OnapCommandConstants.NAME.equals(key)) {
453 set.add(String.valueOf(entry.getValue()));
465 * @param authAction login/logout
467 * @throws OnapCommandException
469 public static OnapCommand findAuthCommand(OnapHttpCommand forCmd, String authAction) throws OnapCommandException {
470 OnapCommand auth = null;
472 //mrkanag: fix this to discover the auth command by matching info->product & service
473 auth = OnapCommandRegistrar.getRegistrar().get(
474 forCmd.getInfo().getService() + "-" +
475 forCmd.getService().getAuthType() + "-" + authAction,
476 forCmd.getInfo().getProduct());
477 } catch (OnapCommandNotFound e) { // NOSONAR
478 auth = OnapCommandRegistrar.getRegistrar().get(
479 forCmd.getService().getAuthType() + "-" + authAction,
480 forCmd.getInfo().getProduct());