Ignore those exceptions never occurs
[cli.git] / profiles / http / src / main / java / org / onap / cli / fw / http / schema / OnapCommandSchemaHttpLoader.java
1 /*
2  * Copyright 2017 Huawei Technologies Co., Ltd.
3  *
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
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 package org.onap.cli.fw.http.schema;
18
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;
24 import java.util.Map;
25 import java.util.Map.Entry;
26 import java.util.Set;
27 import java.util.stream.Collectors;
28
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;
43
44 import com.fasterxml.jackson.databind.ObjectMapper;
45
46 import net.minidev.json.JSONObject;
47
48 public class OnapCommandSchemaHttpLoader {
49
50     public static List<String> loadHttpSchema(OnapHttpCommand cmd, String schemaName, boolean includeDefault,
51                                           boolean validateSchema) throws OnapCommandException {
52         try {
53             List<String> errors = new ArrayList<>();
54             if (includeDefault) {
55                 Map<String, ?> defaultParameterMap = includeDefault ?
56                         OnapCommandSchemaLoader.validateSchemaVersion(OnapCommandHttpConstants.DEFAULT_PARAMETER_HTTP_FILE_NAME, cmd.getSchemaVersion()) : new HashMap<>();
57
58                 //mrkanag default_parameter is supported only for parameters.
59                 if (defaultParameterMap.containsKey(OnapCommandConstants.INFO)) {
60                     defaultParameterMap.remove(OnapCommandConstants.INFO);
61                 }
62
63                 errors.addAll(OnapCommandSchemaLoader.parseSchema(cmd, defaultParameterMap, validateSchema));
64             }
65
66             Map<String, List<Map<String, String>>> commandYamlMap =
67                     (Map<String, List<Map<String, String>>>)OnapCommandSchemaLoader.validateSchemaVersion(schemaName, cmd.getSchemaVersion());
68
69             errors.addAll(parseHttpSchema(cmd, commandYamlMap, validateSchema));
70
71             return errors;
72
73         } catch (OnapCommandException e) {
74             throw e;
75         } catch (Exception e) {
76             throw new OnapCommandInvalidSchema(schemaName, e);
77         }
78     }
79
80     /**
81      * Load the schema.
82      *
83      * @param cmd
84      *            OnapHttpCommand
85      * @param schemaName
86      *            schema name
87      * @throws OnapCommandException
88      *             on error
89      */
90     public static ArrayList<String> parseHttpSchema(OnapHttpCommand cmd,
91                                                     final Map<String, ?> values,
92                                                     boolean validate) throws OnapCommandException {
93         ArrayList<String> errorList = new ArrayList<>();
94         try {
95             Map<String, ?> valMap = (Map<String, ?>) values.get(OnapCommandHttpConstants.HTTP);
96
97             if (valMap != null) {
98                 if (validate) {
99                     OnapCommandUtils.validateTags(errorList, valMap, OnapCommandConfig.getCommaSeparatedList(OnapCommandHttpConstants.HTTP_SECTIONS),
100                             OnapCommandConfig.getCommaSeparatedList(OnapCommandHttpConstants.HTTP_MANDATORY_SECTIONS), OnapCommandHttpConstants.HTTP);
101                     errorList.addAll(validateHttpSchemaSection(values));
102                 }
103                 for (Map.Entry<String, ?> entry1 : valMap.entrySet()) {
104                     String key1 = entry1.getKey();
105
106                     switch (key1) {
107                         case OnapCommandHttpConstants.REQUEST:
108                             Map<String, ?> map = (Map<String, ?>) valMap.get(key1);
109
110                             for (Map.Entry<String, ?> entry2 : map.entrySet()) {
111                                 try {
112                                     String key2 = entry2.getKey();
113
114                                     switch (key2) {
115                                         case OnapCommandHttpConstants.URI:
116                                             Object obj = map.get(key2);
117                                             cmd.getInput().setUri(obj.toString());
118                                             break;
119                                         case OnapCommandHttpConstants.METHOD_TYPE:
120                                             Object method = map.get(key2);
121                                             cmd.getInput().setMethod(method.toString());
122                                             break;
123                                         case OnapCommandHttpConstants.BODY:
124                                             Object body = map.get(key2);
125                                             cmd.getInput().setBody(body.toString());
126                                             break;
127                                         case OnapCommandHttpConstants.HEADERS:
128                                             Map<String, String> head = (Map<String, String>) map.get(key2);
129                                             cmd.getInput().setReqHeaders(head);
130                                             break;
131                                         case OnapCommandHttpConstants.QUERIES:
132                                             Map<String, String> query = (Map<String, String>) map.get(key2);
133
134                                             cmd.getInput().setReqQueries(query);
135                                             break;
136                                         case OnapCommandHttpConstants.MULTIPART_ENTITY_NAME:
137                                             Object multipartEntityName = map.get(key2);
138                                             cmd.getInput().setMultipartEntityName(multipartEntityName.toString());
139                                             break;
140                                     }
141                                 }catch (Exception ex) {
142                                     OnapCommandUtils.throwOrCollect(new OnapCommandInvalidSchema(cmd.getSchemaName(), ex), errorList, validate);
143                                 }
144                             }
145                             break;
146
147                         case OnapCommandHttpConstants.SERVICE:
148                             Map<String, String> serviceMap = (Map<String, String>) valMap.get(key1);
149
150                             if (serviceMap != null) {
151                                 if (validate) {
152                                     OnapCommandUtils.validateTags(errorList, (Map<String, Object>) valMap.get(key1),
153                                             OnapCommandConfig.getCommaSeparatedList(OnapCommandHttpConstants.SERVICE_PARAMS_LIST),
154                                             OnapCommandConfig.getCommaSeparatedList(OnapCommandHttpConstants.SERVICE_PARAMS_MANDATORY_LIST), OnapCommandHttpConstants.SERVICE);
155
156                                     HashMap<String, String> validationMap = new HashMap<>();
157                                     validationMap.put(OnapCommandHttpConstants.AUTH, OnapCommandHttpConstants.AUTH_VALUES);
158                                     validationMap.put(OnapCommandHttpConstants.MODE, OnapCommandHttpConstants.MODE_VALUES);
159
160                                     for (String secKey : validationMap.keySet()) {
161                                         if (serviceMap.containsKey(secKey)) {
162                                             Object obj = serviceMap.get(secKey);
163                                             if (obj == null) {
164                                                 errorList.add("Attribute '" + secKey + "' under '" + OnapCommandHttpConstants.SERVICE + "' is empty");
165                                             } else {
166                                                 String value = String.valueOf(obj);
167                                                 if (!OnapCommandConfig.getCommaSeparatedList(validationMap.get(secKey)).contains(value)) {
168                                                     errorList.add("Attribute '" + secKey + "' contains invalid value. Valide values are "
169                                                             + OnapCommandConfig.getCommaSeparatedList(validationMap.get(key1))); //
170                                                 }
171                                             }
172                                         }
173                                     }
174                                 }
175
176                                 OnapCommandHttpService srv = new OnapCommandHttpService();
177
178                                 for (Map.Entry<String, String> entry : serviceMap.entrySet()) {
179                                     String key = entry.getKey();
180
181                                     switch (key) {
182                                         case OnapCommandConstants.NAME:
183                                             srv.setName(serviceMap.get(key));
184                                             break;
185
186                                         case OnapCommandHttpConstants.VERSION:
187                                             srv.setVersion(serviceMap.get(key).toString());
188                                             break;
189
190                                         case OnapCommandHttpConstants.AUTH:
191                                             Object obj = serviceMap.get(key);
192                                             srv.setAuthType(obj.toString());
193                                             break;
194
195                                         case OnapCommandHttpConstants.MODE:
196                                             Object mode = serviceMap.get(key);
197                                             srv.setMode(mode.toString());
198                                             break;
199                                     }
200                                 }
201
202                                 cmd.setService(srv);
203                             }
204                             break;
205
206                         case OnapCommandHttpConstants.SUCCESS_CODES:
207                             if (validate) {
208                                 validateHttpSccessCodes(errorList, (List<Object>) valMap.get(key1));
209                             }
210                             cmd.setSuccessStatusCodes((ArrayList) valMap.get(key1));
211                             break;
212
213                         case OnapCommandHttpConstants.RESULT_MAP:
214                             if (validate) {
215                                 validateHttpResultMap(errorList, values);
216                             }
217                             cmd.setResultMap((Map<String, String>) valMap.get(key1));
218                             break;
219
220                         case OnapCommandHttpConstants.SAMPLE_RESPONSE:
221                             // (mrkanag) implement sample response handling
222                             break;
223                     }
224                 }
225             }
226         }catch (OnapCommandException e) {
227             OnapCommandUtils.throwOrCollect(e, errorList, validate);
228         }
229
230         //Handle the parameters for auth:
231         // for commands, copy params from login command to this command
232         if (!cmd.getService().isNoAuth()) {
233             if (cmd.getInfo().getCommandType().equals(OnapCommandType.AUTH)) {
234                 OnapCommandUtils.throwOrCollect(new OnapCommandInvalidSchema(
235                         cmd.getSchemaName(), "For auth type commands, http->service->auth should be none"),
236                         errorList,
237                         validate);
238             } else {
239                 OnapCommand login = OnapCommandSchemaHttpLoader.findAuthCommand(cmd, "login");
240                 OnapCommandUtils.copyParamSchemasFrom(login, cmd);
241             }
242         } else {
243             //with service->auth: none,
244             //normal cmd: ignore all auth parms
245             if (!cmd.getInfo().getCommandType().equals(OnapCommandType.AUTH)) {
246                 cmd.getParametersMap().get(OnapCommandHttpConstants.DEAFULT_PARAMETER_USERNAME).setInclude(false);
247                 cmd.getParametersMap().get(OnapCommandHttpConstants.DEAFULT_PARAMETER_PASSWORD).setInclude(false);
248                 cmd.getParametersMap().get(OnapCommandHttpConstants.DEFAULT_PARAMETER_NO_AUTH).setInclude(false);
249             } else {
250                 //auth: login and logout commands, ignore no-auth
251                 cmd.getParametersMap().get(OnapCommandHttpConstants.DEFAULT_PARAMETER_NO_AUTH).setInclude(false);
252                 //auth: only for logout commands, ignore username and password too
253                 if (!cmd.getName().endsWith(OnapCommandHttpConstants.AUTH_SERVICE_LOGIN)) {
254                     cmd.getParametersMap().get(OnapCommandHttpConstants.DEAFULT_PARAMETER_USERNAME).setInclude(false);
255                     cmd.getParametersMap().get(OnapCommandHttpConstants.DEAFULT_PARAMETER_PASSWORD).setInclude(false);
256                 }
257             }
258         }
259
260         return errorList;
261     }
262
263     public static ArrayList<String> validateHttpSchemaSection(Map<String, ?> values) {
264         ArrayList<String> errorList = new ArrayList<>();
265         Map<String, ?> map = (Map<String, ?>) values.get(OnapCommandHttpConstants.HTTP);
266         Map<String, Object> requestMap = (Map<String, Object>) map.get(OnapCommandHttpConstants.REQUEST);
267
268         if (requestMap != null && !requestMap.isEmpty()) {
269             OnapCommandUtils.validateTags(errorList, requestMap, OnapCommandConfig.getCommaSeparatedList(OnapCommandHttpConstants.HTTP_REQUEST_PARAMS),
270                     OnapCommandConfig.getCommaSeparatedList(OnapCommandHttpConstants.HTTP_REQUEST_MANDATORY_PARAMS), OnapCommandHttpConstants.REQUEST);
271             String method = (String) requestMap.get(OnapCommandHttpConstants.METHOD);
272             if (method != null && !method.isEmpty()) {
273                 if (!OnapCommandConfig.getCommaSeparatedList(OnapCommandHttpConstants.HTTP_METHODS).contains(method.toLowerCase())) {
274                     errorList.add("Attribute '" + OnapCommandHttpConstants.METHOD + "' under '" + OnapCommandHttpConstants.REQUEST + "' is invalid, correct types are "
275                             + OnapCommandConfig.getCommaSeparatedList(OnapCommandHttpConstants.HTTP_METHODS).toString());
276                 }
277             } else {
278                 errorList.add("Http request method cann't be null or empty");
279             }
280
281             Set<String> requestParams = getRequestParams(values);
282
283             Set<String> uriParams = validateHttpUri(errorList, requestMap);
284
285             Set<String> bodyParams = validateHttpBody(errorList, requestMap);
286
287             Set<String> headerParams = validateHttpHeaders(requestMap);
288
289             Set<String> queryParams = validateHttpQueries(requestMap);
290
291             HashSet<String> totoalParams = new HashSet<>(uriParams);
292             totoalParams.addAll(bodyParams);
293             totoalParams.addAll(headerParams);
294             totoalParams.addAll(queryParams);
295
296             List<String> nonDeclaredParams = totoalParams.stream().filter(param -> !requestParams.contains(param))
297                     .collect(Collectors.toList());
298
299             nonDeclaredParams.stream().forEach(p -> errorList.add("The parameter '" + p
300                     + "' declared under 'parameters:' section is not mapped into request section."));
301         } else {
302             errorList.add(OnapCommandUtils.emptySection(OnapCommandHttpConstants.REQUEST));
303         }
304         return errorList;
305     }
306
307     public static void validateHttpSccessCodes(List<String> errorList, List<Object> requestSuccessCodes) {
308
309         if (requestSuccessCodes == null || requestSuccessCodes.isEmpty()) {
310             errorList.add(OnapCommandHttpConstants.HTTP_SUCCESS_CODE_INVALID);
311             return;
312         }
313
314         for (Object successCode : requestSuccessCodes) {
315             Integer code = (Integer) successCode;
316             if (code < 200 || code >= 300) {
317                 if ( code != 404) {
318                     errorList.add(OnapCommandHttpConstants.HTTP_SUCCESS_CODE_INVALID);
319                 }
320             }
321         }
322
323     }
324
325     public static void validateHttpResultMap(List<String> errorList, Map<String, ?> values) throws OnapCommandException {
326         Map<String, ?> valMap = (Map<String, ?>) values.get(OnapCommandHttpConstants.HTTP);
327         List<Map<String, String>> attributes = (List<Map<String, String>>) ((Map<String, ?>)values.get(OnapCommandConstants.RESULTS)).get(OnapCommandConstants.ATTRIBUTES);
328         Set<String> resultMapParams = ((Map<String, String>) valMap.get(OnapCommandHttpConstants.RESULT_MAP)).keySet();
329
330         Set<String> resultAttNames = attributes.stream().map(map -> map.get(OnapCommandConstants.NAME))
331                 .collect(Collectors.toSet());
332
333         List<String> invaliResultMapParams = resultMapParams.stream()
334                 .filter(p -> !resultAttNames.contains(p)).collect(Collectors.toList());
335
336         if (!invaliResultMapParams.isEmpty()) {
337             OnapCommandUtils.throwOrCollect(new OnapCommandHttpInvalidResultMap(invaliResultMapParams), errorList, true);
338         }
339     }
340
341     public static Set<String> validateHttpQueries(Map<String, Object> requestMap) {
342         Map<String, Object> queries = (Map<String, Object>) requestMap.get(OnapCommandHttpConstants.QUERIES);
343         Set<String> queryParamNames = new HashSet<>();
344         if (queries != null) {
345             for (Entry<String, Object> entry : queries.entrySet()) {
346                 OnapCommandUtils.parseParameters(String.valueOf(entry.getValue()), queryParamNames);
347             }
348         }
349         return queryParamNames;
350     }
351
352     public static Set<String> validateHttpHeaders(Map<String, Object> requestMap) {
353
354         Map<String, Object> headers = (Map<String, Object>) requestMap.get(OnapCommandHttpConstants.HEADERS);
355         Set<String> headerParamNames = new HashSet<>();
356         if (headers != null) {
357             for (Entry<String, Object> entry : headers.entrySet()) {
358                 OnapCommandUtils.parseParameters(String.valueOf(entry.getValue()), headerParamNames);
359             }
360         }
361         return headerParamNames;
362     }
363
364     public static Set<String> validateHttpBody(List<String> errorList, Map<String, Object> requestMap) {
365         Set<String> bodyParamNames = new HashSet<>();
366         Object bodyString = requestMap.get(OnapCommandHttpConstants.BODY);
367         if (bodyString == null) {
368             return bodyParamNames;
369         }
370
371         String body = String.valueOf(bodyString);
372         JSONObject obj = null;
373         try {
374             obj = new ObjectMapper().readValue(body, JSONObject.class);
375         } catch (IOException e1) { // NOSONAR
376             errorList.add(OnapCommandHttpConstants.HTTP_BODY_FAILED_PARSING);
377         }
378         if (obj == null || "".equals(obj.toString())) {
379             errorList.add(OnapCommandHttpConstants.HTTP_BODY_JSON_EMPTY);
380         }
381         OnapCommandUtils.parseParameters(body, bodyParamNames);
382
383         return bodyParamNames;
384     }
385
386     public static Set<String> validateHttpUri(List<String> errorList, Map<String, Object> requestMap) {
387         Set<String> uriParamNames = new HashSet<>();
388         String uri = (String) requestMap.get(OnapCommandHttpConstants.URI);
389         if (uri == null || uri.isEmpty()) {
390             errorList.add(OnapCommandUtils.emptySection(OnapCommandHttpConstants.URI));
391             return uriParamNames;
392         }
393         OnapCommandUtils.parseParameters(uri, uriParamNames);
394         return uriParamNames;
395     }
396
397     public static Set<String> getRequestParams(Map<String, ?> yamlMap) {
398
399         Set<String> set = new HashSet<>();
400
401         @SuppressWarnings("unchecked")
402         List<Map<String, Object>> inputParams = (List<Map<String, Object>>) yamlMap.get(OnapCommandConstants.PARAMETERS);
403
404         if (inputParams != null) {
405             for (Map<String, Object> map : inputParams) {
406                 for (Entry<String, Object> entry : map.entrySet()) {
407                     Object key = entry.getKey();
408
409                     if (OnapCommandConstants.NAME.equals(key)) {
410                         set.add(String.valueOf(entry.getValue()));
411                         break;
412                     }
413                 }
414             }
415         }
416
417         return set;
418     }
419
420     /**
421         *
422         * @param authAction login/logout
423         * @return
424         * @throws OnapCommandException
425         */
426        public static OnapCommand findAuthCommand(OnapHttpCommand forCmd, String authAction) throws OnapCommandException {
427            OnapCommand auth = null;
428            try {
429                //mrkanag: fix this to discover the auth command by matching info->product & service
430                auth = OnapCommandRegistrar.getRegistrar().get(
431                        forCmd.getInfo().getService() + "-" +
432                        forCmd.getService().getAuthType() + "-" + authAction,
433                        forCmd.getInfo().getProduct());
434            } catch (OnapCommandNotFound e) {  // NOSONAR
435                auth = OnapCommandRegistrar.getRegistrar().get(
436                        forCmd.getService().getAuthType() + "-" + authAction,
437                        forCmd.getInfo().getProduct());
438            }
439
440            return auth;
441        }
442
443
444 }