code improvements- incorporating comments
[cli.git] / framework / src / main / java / org / onap / cli / fw / schema / OnapCommandSchemaLoader.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.schema;
18
19 import static org.onap.cli.fw.conf.OnapCommandConstants.ATTRIBUTES;
20 import static org.onap.cli.fw.conf.OnapCommandConstants.BOOLEAN_TRUE;
21 import static org.onap.cli.fw.conf.OnapCommandConstants.COMMAND_TYPE_VALUES;
22 import static org.onap.cli.fw.conf.OnapCommandConstants.DEFAULT_PARAMETER_FILE_NAME;
23 import static org.onap.cli.fw.conf.OnapCommandConstants.DEFAULT_VALUE;
24 import static org.onap.cli.fw.conf.OnapCommandConstants.DESCRIPTION;
25 import static org.onap.cli.fw.conf.OnapCommandConstants.DIRECTION;
26 import static org.onap.cli.fw.conf.OnapCommandConstants.INFO;
27 import static org.onap.cli.fw.conf.OnapCommandConstants.INFO_AUTHOR;
28 import static org.onap.cli.fw.conf.OnapCommandConstants.INFO_IGNORE;
29 import static org.onap.cli.fw.conf.OnapCommandConstants.INFO_PARAMS_LIST;
30 import static org.onap.cli.fw.conf.OnapCommandConstants.INFO_PARAMS_MANDATORY_LIST;
31 import static org.onap.cli.fw.conf.OnapCommandConstants.INFO_PRODUCT;
32 import static org.onap.cli.fw.conf.OnapCommandConstants.INFO_SERVICE;
33 import static org.onap.cli.fw.conf.OnapCommandConstants.INFO_STATE;
34 import static org.onap.cli.fw.conf.OnapCommandConstants.INFO_TYPE;
35 import static org.onap.cli.fw.conf.OnapCommandConstants.INPUT_PARAMS_LIST;
36 import static org.onap.cli.fw.conf.OnapCommandConstants.INPUT_PARAMS_MANDATORY_LIST;
37 import static org.onap.cli.fw.conf.OnapCommandConstants.IS_DEFAULT_ATTR;
38 import static org.onap.cli.fw.conf.OnapCommandConstants.IS_DEFAULT_PARAM;
39 import static org.onap.cli.fw.conf.OnapCommandConstants.IS_INCLUDE;
40 import static org.onap.cli.fw.conf.OnapCommandConstants.IS_OPTIONAL;
41 import static org.onap.cli.fw.conf.OnapCommandConstants.IS_SECURED;
42 import static org.onap.cli.fw.conf.OnapCommandConstants.LONG_OPTION;
43 import static org.onap.cli.fw.conf.OnapCommandConstants.NAME;
44 import static org.onap.cli.fw.conf.OnapCommandConstants.OPEN_CLI_SCHEMA_VERSION;
45 import static org.onap.cli.fw.conf.OnapCommandConstants.PARAMETERS;
46 import static org.onap.cli.fw.conf.OnapCommandConstants.RESULTS;
47 import static org.onap.cli.fw.conf.OnapCommandConstants.RESULT_PARAMS_LIST;
48 import static org.onap.cli.fw.conf.OnapCommandConstants.RESULT_PARAMS_MANDATORY_LIST;
49 import static org.onap.cli.fw.conf.OnapCommandConstants.SCHEMA_FILE_NOT_EXIST;
50 import static org.onap.cli.fw.conf.OnapCommandConstants.SCHEMA_FILE_WRONG_EXTN;
51 import static org.onap.cli.fw.conf.OnapCommandConstants.SCHEMA_PATH_PATERN;
52 import static org.onap.cli.fw.conf.OnapCommandConstants.SCOPE;
53 import static org.onap.cli.fw.conf.OnapCommandConstants.SHORT_OPTION;
54 import static org.onap.cli.fw.conf.OnapCommandConstants.TOP_LEVEL_MANDATORY_LIST;
55 import static org.onap.cli.fw.conf.OnapCommandConstants.TOP_LEVEL_PARAMS_LIST;
56 import static org.onap.cli.fw.conf.OnapCommandConstants.TYPE;
57
58 import java.io.File;
59 import java.io.FileInputStream;
60 import java.io.FileNotFoundException;
61 import java.io.IOException;
62 import java.io.InputStream;
63 import java.util.ArrayList;
64 import java.util.Arrays;
65 import java.util.HashMap;
66 import java.util.HashSet;
67 import java.util.List;
68 import java.util.Map;
69 import java.util.Set;
70
71 import org.onap.cli.fw.cmd.OnapCommand;
72 import org.onap.cli.fw.cmd.OnapCommandType;
73 import org.onap.cli.fw.conf.OnapCommandConfig;
74 import org.onap.cli.fw.conf.OnapCommandConstants;
75 import org.onap.cli.fw.error.OnapCommandException;
76 import org.onap.cli.fw.error.OnapCommandInvalidSchema;
77 import org.onap.cli.fw.error.OnapCommandInvalidSchemaVersion;
78 import org.onap.cli.fw.error.OnapCommandParameterNameConflict;
79 import org.onap.cli.fw.error.OnapCommandParameterOptionConflict;
80 import org.onap.cli.fw.error.OnapCommandSchemaNotFound;
81 import org.onap.cli.fw.info.OnapCommandInfo;
82 import org.onap.cli.fw.info.OnapCommandState;
83 import org.onap.cli.fw.input.OnapCommandParameter;
84 import org.onap.cli.fw.input.OnapCommandParameterType;
85 import org.onap.cli.fw.output.OnapCommandPrintDirection;
86 import org.onap.cli.fw.output.OnapCommandResultAttribute;
87 import org.onap.cli.fw.output.OnapCommandResultAttributeScope;
88 import org.onap.cli.fw.utils.OnapCommandDiscoveryUtils;
89 import org.onap.cli.fw.utils.OnapCommandUtils;
90 import org.springframework.core.io.Resource;
91
92 public class OnapCommandSchemaLoader {
93
94     private OnapCommandSchemaLoader() {
95         // As per the java guidelines
96     }
97
98     /**
99      * Validates schema version.
100      *
101      * @param schemaName schema name
102      * @param version    schema version
103      * @return map
104      * @throws OnapCommandInvalidSchemaVersion invalid schema version exception
105      * @throws OnapCommandInvalidSchema        invalid schema
106      * @throws OnapCommandSchemaNotFound       schema not found
107      */
108     public static Map<String, Object> validateSchemaVersion(String schemaName, String version) throws OnapCommandException {
109         Map<String, Object> values = null;
110         try {
111             InputStream inputStream = OnapCommandUtils.class.getClassLoader().getResourceAsStream(schemaName);
112
113             Resource resource = OnapCommandDiscoveryUtils.findResource(schemaName, SCHEMA_PATH_PATERN);
114
115             if (resource != null) {
116                 inputStream = resource.getInputStream();
117             }
118
119             if (inputStream == null) {
120                 inputStream = loadSchemaFromFile(schemaName);
121             }
122
123             values = loadSchema(inputStream, schemaName);
124             String schemaVersion = "";
125             if (values.keySet().contains(OPEN_CLI_SCHEMA_VERSION)) {
126                 Object obj = values.get(OPEN_CLI_SCHEMA_VERSION);
127                 schemaVersion = obj.toString();
128             }
129
130             if (!version.equals(schemaVersion)) {
131                 throw new OnapCommandInvalidSchemaVersion(schemaVersion);
132             }
133             inputStream.close();
134         } catch (IOException e) {
135             throw new OnapCommandSchemaNotFound(schemaName, e);
136         }
137         return values;
138     }
139
140     /**
141      * Retrieve OnapCommand from schema.
142      *
143      * @param cmd            OnapCommand
144      * @param schemaName     schema name
145      * @param includeDefault include if default
146      * @param validateSchema flag to represent validation
147      * @throws OnapCommandException  on error
148      */
149     public static List<String> loadSchema(OnapCommand cmd, String schemaName, boolean includeDefault,
150                                           boolean validateSchema) throws OnapCommandException {
151         try {
152             List<String> errors = new ArrayList<>();
153             if (includeDefault) {
154                 Map<String, ?> defaultParameterMap = validateSchemaVersion(DEFAULT_PARAMETER_FILE_NAME, cmd.getSchemaVersion());
155                 //mrkanag default_parameter is supported only for parameters.
156                 if (defaultParameterMap.containsKey(INFO)) {
157                     defaultParameterMap.remove(OnapCommandConstants.INFO);
158                 }
159
160                 errors.addAll(parseSchema(cmd, defaultParameterMap, validateSchema));
161             }
162
163             Map<String, Object> commandYamlMap = validateSchemaVersion(schemaName, cmd.getSchemaVersion());
164
165             errors.addAll(parseSchema(cmd, commandYamlMap, validateSchema));
166
167             return errors;
168         } catch (OnapCommandException e) {
169             throw e;
170         } catch (Exception e) {
171             throw new OnapCommandInvalidSchema(schemaName, e);
172         }
173     }
174
175     public static List<String> parseSchema(OnapCommand cmd,
176                                             final Map<String, ?> values,
177                                             boolean validate) throws OnapCommandException {
178
179         List<String> exceptionList = new ArrayList<>();
180         List<String> shortOptions = new ArrayList<>();
181         List<String> longOptions = new ArrayList<>();
182
183         if (validate) {
184             OnapCommandUtils.validateTags(exceptionList, (Map<String, Object>) values, OnapCommandConfig.getCommaSeparatedList(TOP_LEVEL_PARAMS_LIST),
185                     OnapCommandConfig.getCommaSeparatedList(TOP_LEVEL_MANDATORY_LIST), "root level");
186         }
187
188
189         List<String> sections = Arrays.asList(NAME, DESCRIPTION, INFO, PARAMETERS, RESULTS);
190
191         for (String key : sections) {
192
193             switch (key) {
194                 case NAME:
195                     Object val = values.get(key);
196                     if (val != null) {
197                         cmd.setName(val.toString());
198                     }
199                     break;
200
201                 case DESCRIPTION:
202                     Object description = values.get(key);
203                     if (description != null) {
204                         cmd.setDescription(description.toString());
205                     }
206                     break;
207
208                 case INFO:
209                     Map<String, String> infoMap = (Map<String, String>) values.get(key);
210
211                     if (infoMap != null) {
212                         if (validate) {
213                             OnapCommandUtils.validateTags(exceptionList, (Map<String, Object>) values.get(key),
214                                     OnapCommandConfig.getCommaSeparatedList(INFO_PARAMS_LIST),
215                                     OnapCommandConfig.getCommaSeparatedList(INFO_PARAMS_MANDATORY_LIST), INFO);
216
217                             HashMap<String, String> validationMap = new HashMap<>();
218                             validationMap.put(INFO_TYPE, COMMAND_TYPE_VALUES);
219
220                             for (Map.Entry<String,String> entry : validationMap.entrySet()) {
221                                 String secKey=entry.getKey();
222                                 if (infoMap.containsKey(secKey)) {
223                                     String value = infoMap.get(secKey);
224                                     if (value == null) {
225                                         exceptionList.add("Attribute '" + secKey + "' under '" + INFO + "' is empty");
226                                     } else {
227                                         if (!OnapCommandConfig.getCommaSeparatedList(validationMap.get(secKey)).contains(value)) {
228                                             exceptionList.add("Attribute '" + secKey + "' contains invalid value. Valide values are "
229                                                     + OnapCommandConfig.getCommaSeparatedList(validationMap.get(key))); //
230                                         }
231                                     }
232                                 }
233                             }
234                         }
235
236                         OnapCommandInfo info = new OnapCommandInfo();
237
238                         for (Map.Entry<String, String> entry1 : infoMap.entrySet()) {
239                             String key1 = entry1.getKey();
240
241                             switch (key1) {
242                                 case INFO_PRODUCT:
243                                     info.setProduct(infoMap.get(key1));
244                                     break;
245
246                                 case INFO_SERVICE:
247                                     info.setService(infoMap.get(key1));
248                                     break;
249
250                                 case INFO_TYPE:
251                                     Object obj = infoMap.get(key1);
252                                     info.setCommandType(OnapCommandType.get(obj.toString()));
253                                     break;
254
255                                 case INFO_STATE:
256                                     Object state = infoMap.get(key1);
257                                     info.setState(OnapCommandState.get(state.toString()));
258                                     break;
259
260                                 case INFO_AUTHOR:
261                                     Object mode = infoMap.get(key1);
262                                     info.setAuthor(mode.toString());
263                                     break;
264
265                                 case INFO_IGNORE:
266                                     Object ignore = infoMap.get(key1);
267                                     info.setIgnore(ignore.toString().equalsIgnoreCase(OnapCommandConstants.BOOLEAN_TRUE));
268                                     break;
269                                 default : // Do nothing
270                             }
271                         }
272
273                         cmd.setInfo(info);
274                     }
275                     break;
276
277                 case PARAMETERS:
278
279                     List<Map<String, String>> parameters = (List) values.get(key);
280
281                     if (parameters != null) {
282                         Set<String> names = new HashSet<>();
283
284                         for (Map<String, String> parameter : parameters) {
285                             OnapCommandParameter param = new OnapCommandParameter();
286
287                             if (validate) {
288                                 OnapCommandUtils.validateTags(exceptionList, parameter, OnapCommandConfig.getCommaSeparatedList(INPUT_PARAMS_LIST),
289                                         OnapCommandConfig.getCommaSeparatedList(INPUT_PARAMS_MANDATORY_LIST), PARAMETERS);
290                             }
291
292                             for (Map.Entry<String, String> entry1 : parameter.entrySet()) {
293                                 String key2 = entry1.getKey();
294
295                                 switch (key2) {
296                                     case NAME:
297                                         if (names.contains(parameter.get(key2))) {
298                                             OnapCommandUtils.throwOrCollect(new OnapCommandParameterNameConflict(parameter.get(key2)), exceptionList, validate);
299                                         } else {
300                                             names.add(parameter.get(key2));
301                                         }
302
303                                         param.setName(parameter.get(key2));
304                                         break;
305
306                                     case DESCRIPTION:
307                                         param.setDescription(parameter.get(key2));
308                                         break;
309
310                                     case SHORT_OPTION:
311                                         if (shortOptions.contains(parameter.get(key2))) {
312                                             OnapCommandUtils.throwOrCollect(new OnapCommandParameterOptionConflict(
313                                                     cmd.getSchemaName(),
314                                                     parameter.get(key2)), exceptionList, validate);
315                                         }
316                                         shortOptions.add(parameter.get(key2));
317                                         param.setShortOption(parameter.get(key2));
318                                         break;
319
320                                     case LONG_OPTION:
321                                         if (longOptions.contains(parameter.get(key2))) {
322                                             OnapCommandUtils.throwOrCollect(new OnapCommandParameterOptionConflict(
323                                                     cmd.getSchemaName(),
324                                                     parameter.get(key2)), exceptionList, validate);
325                                         }
326                                         longOptions.add(parameter.get(key2));
327                                         param.setLongOption(parameter.get(key2));
328                                         break;
329
330                                     case DEFAULT_VALUE:
331                                         Object obj = parameter.get(key2);
332                                         param.setRawDefaultValue(obj.toString());
333                                         break;
334
335                                     case TYPE:
336                                         try {
337                                             param.setParameterType(OnapCommandParameterType.get(parameter.get(key2)));
338                                         } catch (OnapCommandException ex) {
339                                             OnapCommandUtils.throwOrCollect(ex, exceptionList, validate);
340                                         }
341                                         break;
342
343                                     case IS_OPTIONAL:
344                                         if (validate && !OnapCommandUtils.validateBoolean(String.valueOf(parameter.get(key2)))) {
345                                             exceptionList.add(OnapCommandUtils.invalidBooleanValueMessage(parameter.get(NAME),
346                                                     IS_OPTIONAL, String.valueOf(parameter.get(key2))));
347                                         }
348
349                                         param.setOptional(BOOLEAN_TRUE.equalsIgnoreCase(String.valueOf(parameter.get(key2))));
350                                         break;
351
352                                     case IS_SECURED:
353                                             if (validate && !OnapCommandUtils.validateBoolean(String.valueOf(parameter.get(key2)))) {
354                                                 exceptionList.add(OnapCommandUtils.invalidBooleanValueMessage(parameter.get(NAME),
355                                                         IS_SECURED, String.valueOf(parameter.get(key2))));
356                                             }
357
358                                         param.setSecured(BOOLEAN_TRUE.equalsIgnoreCase(String.valueOf(parameter.get(key2))));
359                                         break;
360
361                                     case IS_INCLUDE:
362                                         if (validate && !OnapCommandUtils.validateBoolean(String.valueOf(parameter.get(key2)))) {
363                                             exceptionList.add(OnapCommandUtils.invalidBooleanValueMessage(parameter.get(NAME),
364                                                     IS_INCLUDE, String.valueOf(parameter.get(key2))));
365                                         }
366
367                                         param.setInclude(BOOLEAN_TRUE.equalsIgnoreCase(String.valueOf(parameter.get(key2))));
368                                         break;
369
370                                     case IS_DEFAULT_PARAM:
371                                             if (validate && !OnapCommandUtils.validateBoolean(String.valueOf(parameter.get(key2)))) {
372                                                 exceptionList.add(OnapCommandUtils.invalidBooleanValueMessage(parameter.get(NAME),
373                                                         IS_DEFAULT_PARAM, String.valueOf(parameter.get(key2))));
374                                             }
375
376                                         param.setDefaultParam(BOOLEAN_TRUE.equalsIgnoreCase(String.valueOf(parameter.get(key2))));
377                                         break;
378                                     default : // Do nothing
379                                 }
380                             }
381
382                             cmd.getParameters().add(param);
383                         }
384                     }
385                     break;
386
387                 case RESULTS:
388                     Map<String, ?> valueMap = (Map<String, ?>) values.get(key);
389                     if (valueMap != null) {
390                         for (Map.Entry<String, ?> entry1 : valueMap.entrySet()) {
391                             String key3 = entry1.getKey();
392
393                             switch (key3) {
394                                 case DIRECTION:
395                                     try {
396                                         cmd.getResult().setPrintDirection(OnapCommandPrintDirection.get((String) valueMap.get(key3)));
397                                     } catch (OnapCommandException ex) {
398                                         OnapCommandUtils.throwOrCollect(ex, exceptionList, validate);
399                                     }
400                                     break;
401
402                                 case ATTRIBUTES:
403                                     List<Map<String, String>> attrs = (ArrayList) valueMap.get(key3);
404
405                                     for (Map<String, String> map : attrs) {
406                                         OnapCommandResultAttribute attr = new OnapCommandResultAttribute();
407                                         if (validate) {
408                                             OnapCommandUtils.validateTags(exceptionList, map, OnapCommandConfig.getCommaSeparatedList(RESULT_PARAMS_LIST),
409                                                     OnapCommandConfig.getCommaSeparatedList(RESULT_PARAMS_MANDATORY_LIST), ATTRIBUTES);
410                                         }
411
412                                         Set<String> resultParamNames = new HashSet<>();
413
414                                         for (Map.Entry<String, String> entry4 : map.entrySet()) {
415                                             String key4 = entry4.getKey();
416
417                                             switch (key4) {
418                                                 case NAME:
419                                                     if (resultParamNames.contains(map.get(key4))) {
420                                                         exceptionList.add("Attribute name='" + map.get(key4) + "' under '"
421                                                                 + ATTRIBUTES + ":' is already used, Take different one.");
422
423                                                     } else {
424                                                         attr.setName(map.get(key4));
425                                                         resultParamNames.add(map.get(key4));
426                                                     }
427                                                     break;
428
429                                                 case DESCRIPTION:
430                                                     attr.setDescription(map.get(key4));
431                                                     break;
432
433                                                 case SCOPE:
434                                                     try {
435                                                         attr.setScope(OnapCommandResultAttributeScope.get(map.get(key4)));
436                                                     } catch (OnapCommandException ex) {
437                                                         OnapCommandUtils.throwOrCollect(ex, exceptionList, validate);
438                                                     }
439                                                     break;
440
441                                                 case TYPE:
442                                                     try {
443                                                         attr.setType(OnapCommandParameterType.get(map.get(key4)));
444                                                     } catch (OnapCommandException ex) {
445                                                         OnapCommandUtils.throwOrCollect(ex, exceptionList, validate);
446                                                     }
447                                                     break;
448
449                                                 case DEFAULT_VALUE:
450                                                     Object obj = map.get(key4);
451                                                     attr.setDefaultValue(obj.toString());
452                                                     break;
453
454                                                 case IS_SECURED:
455                                                         if (validate && !OnapCommandUtils.validateBoolean(String.valueOf(map.get(key4)))) {
456                                                             exceptionList.add(OnapCommandUtils.invalidBooleanValueMessage(ATTRIBUTES,
457                                                                     IS_SECURED, String.valueOf(map.get(key4))));
458                                                         }
459                                                     attr.setSecured(BOOLEAN_TRUE.equals(String.valueOf(map.get(key4))));
460                                                     break;
461
462                                                 case IS_DEFAULT_ATTR:
463                                                         if (validate && !OnapCommandUtils.validateBoolean(String.valueOf(map.get(key4)))) {
464                                                             exceptionList.add(OnapCommandUtils.invalidBooleanValueMessage(ATTRIBUTES,
465                                                                     IS_DEFAULT_ATTR, String.valueOf(map.get(key4))));
466                                                         }
467                                                     attr.setDefaultAttr(BOOLEAN_TRUE.equals(String.valueOf(map.get(key4))));
468                                                     break;
469                                                 default : // Do nothing
470                                             }
471
472                                         }
473                                         cmd.getResult().getRecords().add(attr);
474                                     }
475                                     break;
476                                 default : // Do nothing
477                             }
478                         }
479                     }
480                     break;
481                 default : // Do nothing
482             }
483         }
484
485         return exceptionList;
486     }
487
488     public static InputStream loadSchemaFromFile(String schemaLocation) throws OnapCommandInvalidSchema {
489         File schemaFile = new File(schemaLocation);
490         try {
491             FileInputStream inputFileStream = new FileInputStream(schemaFile);  // NOSONAR
492             if (!schemaFile.isFile()) {
493                 throw new OnapCommandInvalidSchema(schemaFile.getName(), SCHEMA_FILE_NOT_EXIST);
494             }
495
496             if (!schemaFile.getName().endsWith(".yaml")) {
497                 throw new OnapCommandInvalidSchema(schemaFile.getName(), SCHEMA_FILE_WRONG_EXTN);
498             }
499             return inputFileStream;
500         }catch (FileNotFoundException e) {
501             throw new OnapCommandInvalidSchema(schemaFile.getName(), e);
502         }
503     }
504
505     /**
506      * Get schema map.
507      *
508      * @param stream
509      * @param schemaName
510      * @return map
511      * @throws OnapCommandInvalidSchema
512      *             exception
513      */
514     public static Map<String, Object> loadSchema(InputStream stream, String schemaName) throws OnapCommandInvalidSchema  { //NOSONAR
515         return OnapCommandDiscoveryUtils.loadYaml(stream);
516
517     }
518 }