Add seed code from Open-O
[cli.git] / framework / src / main / java / org / onap / cli / fw / utils / OnapCommandUtils.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.utils;
18
19 import com.fasterxml.jackson.databind.ObjectMapper;
20 import com.jayway.jsonpath.JsonPath;
21 import net.minidev.json.JSONArray;
22
23 import org.onap.cli.fw.OnapCommand;
24 import org.onap.cli.fw.ad.OnapCredentials;
25 import org.onap.cli.fw.ad.OnapService;
26 import org.onap.cli.fw.cmd.OnapHttpCommand;
27 import org.onap.cli.fw.cmd.OnapSwaggerCommand;
28 import org.onap.cli.fw.conf.Constants;
29 import org.onap.cli.fw.error.OnapCommandDiscoveryFailed;
30 import org.onap.cli.fw.error.OnapCommandException;
31 import org.onap.cli.fw.error.OnapCommandHelpFailed;
32 import org.onap.cli.fw.error.OnapCommandHttpHeaderNotFound;
33 import org.onap.cli.fw.error.OnapCommandHttpInvalidResponseBody;
34 import org.onap.cli.fw.error.OnapCommandInvalidParameterType;
35 import org.onap.cli.fw.error.OnapCommandInvalidParameterValue;
36 import org.onap.cli.fw.error.OnapCommandInvalidPrintDirection;
37 import org.onap.cli.fw.error.OnapCommandInvalidResultAttributeScope;
38 import org.onap.cli.fw.error.OnapCommandInvalidSchema;
39 import org.onap.cli.fw.error.OnapCommandInvalidSchemaVersion;
40 import org.onap.cli.fw.error.OnapCommandParameterNameConflict;
41 import org.onap.cli.fw.error.OnapCommandParameterNotFound;
42 import org.onap.cli.fw.error.OnapCommandParameterOptionConflict;
43 import org.onap.cli.fw.error.OnapCommandResultEmpty;
44 import org.onap.cli.fw.error.OnapCommandResultMapProcessingFailed;
45 import org.onap.cli.fw.error.OnapCommandSchemaNotFound;
46 import org.onap.cli.fw.http.HttpInput;
47 import org.onap.cli.fw.http.HttpResult;
48 import org.onap.cli.fw.input.OnapCommandParameter;
49 import org.onap.cli.fw.input.ParameterType;
50 import org.onap.cli.fw.output.OnapCommandResult;
51 import org.onap.cli.fw.output.OnapCommandResultAttribute;
52 import org.onap.cli.fw.output.OnapCommandResultAttributeScope;
53 import org.onap.cli.fw.output.PrintDirection;
54 import org.onap.cli.fw.output.ResultType;
55 import org.onap.cli.fw.run.OnapCommandExecutor;
56 import org.springframework.core.io.Resource;
57 import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
58 import org.springframework.core.io.support.ResourcePatternResolver;
59 import org.yaml.snakeyaml.Yaml;
60
61 import java.io.File;
62 import java.io.IOException;
63 import java.io.InputStream;
64 import java.util.ArrayList;
65 import java.util.Arrays;
66 import java.util.Collections;
67 import java.util.HashMap;
68 import java.util.List;
69 import java.util.Map;
70 import java.util.Map.Entry;
71 import java.util.ServiceLoader;
72 import java.util.Set;
73
74 /**
75  * Provides helper method to parse Yaml files and produce required objects.
76  *
77  */
78 public class OnapCommandUtils {
79
80     /**
81      * Private constructor.
82      */
83     private OnapCommandUtils() {
84
85     }
86
87     /**
88      * Validates schema version.
89      *
90      * @param schemaName
91      *            schema name
92      * @param version
93      *            schema version
94      * @return map
95      * @throws OnapCommandInvalidSchemaVersion
96      *             invalid schema version exception
97      * @throws OnapCommandInvalidSchema
98      *             invalid schema
99      * @throws OnapCommandSchemaNotFound
100      *             schema not found
101      */
102     public static Map<String, ?> validateSchemaVersion(String schemaName, String version) throws OnapCommandException {
103         InputStream inputStream = OnapCommandUtils.class.getClassLoader().getResourceAsStream(schemaName);
104
105         try {
106             Resource resource = getExternalResource(schemaName, Constants.EXTERNAL_SCHEMA_PATH_PATERN);
107
108             if (resource != null) {
109                 inputStream = resource.getInputStream();
110             }
111
112         } catch (IOException e) {
113             throw new OnapCommandSchemaNotFound(schemaName, e);
114         }
115         if (inputStream == null) {
116             throw new OnapCommandSchemaNotFound(schemaName);
117         }
118
119         Map<String, ?> values = null;
120         try {
121             values = (Map<String, ?>) new Yaml().load(inputStream);
122         } catch (Exception e) {
123             throw new OnapCommandInvalidSchema(schemaName, e);
124         }
125         String schemaVersion = "";
126         if (values.keySet().contains(Constants.ONAP_CMD_SCHEMA_VERSION)) {
127             Object obj = values.get(Constants.ONAP_CMD_SCHEMA_VERSION);
128             schemaVersion = obj.toString();
129         }
130
131         if (!version.equals(schemaVersion)) {
132             throw new OnapCommandInvalidSchemaVersion(schemaVersion);
133         }
134
135         return values;
136     }
137
138     /**
139      * Retrieve OnapCommand from schema.
140      *
141      * @param cmd
142      *            OnapCommand
143      * @param schemaName
144      *            schema name
145      * @param includeDefault
146      *            include if default
147      * @throws OnapCommandParameterNameConflict
148      *             param name conflict exception
149      * @throws OnapCommandParameterOptionConflict
150      *             param option conflict exception
151      * @throws OnapCommandInvalidParameterType
152      *             invalid param type exception
153      * @throws OnapCommandInvalidPrintDirection
154      *             invalid print direction exception
155      * @throws OnapCommandInvalidResultAttributeScope
156      *             invalid scope exception
157      * @throws OnapCommandSchemaNotFound
158      *             schema not found
159      * @throws OnapCommandInvalidSchema
160      *             invalid schema
161      * @throws OnapCommandInvalidSchemaVersion
162      *             invalid schema version
163      */
164     public static void loadSchema(OnapCommand cmd, String schemaName, boolean includeDefault)
165             throws OnapCommandException {
166         List<String> shortOptions = new ArrayList<>();
167         List<String> longOptions = new ArrayList<>();
168         List<String> names = new ArrayList<>();
169
170         if (includeDefault) {
171             loadSchema(cmd, Constants.DEFAULT_PARAMETER_FILE_NAME, shortOptions, longOptions, names);
172         }
173
174         loadSchema(cmd, schemaName, shortOptions, longOptions, names);
175
176     }
177
178     private static void loadSchema(OnapCommand cmd, String schemaName, List<String> shortOptions,
179             List<String> longOptions, List<String> names) throws OnapCommandException {
180         try {
181             Map<String, ?> values = validateSchemaVersion(schemaName, cmd.getSchemaVersion());
182
183             for (Map.Entry<String, ?> entry : values.entrySet()) {
184                 String key = entry.getKey();
185
186                 if (Constants.NAME.equals(key)) {
187                     Object val = values.get(key);
188                     cmd.setName(val.toString());
189                 } else if (Constants.DESCRIPTION.equals(key)) {
190                     Object val = values.get(key);
191                     cmd.setDescription(val.toString());
192                 } else if (Constants.SERVICE.equals(key)) {
193                     Map<String, String> map = (Map<String, String>) values.get(key);
194                     OnapService srv = new OnapService();
195
196                     for (Map.Entry<String, String> entry1 : map.entrySet()) {
197                         String key1 = entry1.getKey();
198
199                         if (Constants.NAME.equals(key1)) {
200                             srv.setName(map.get(key1));
201                         } else if (Constants.VERSION.equals(key1)) {
202                             srv.setVersion(map.get(key1));
203                         } else if (Constants.NO_AUTH.equals(key1)) {
204                             Object obj = map.get(key1);
205                             srv.setNoAuth("true".equalsIgnoreCase(obj.toString()));
206                         }
207                     }
208
209                     cmd.setService(srv);
210                 } else if (Constants.PARAMETERS.equals(key)) {
211                     List<Map<String, String>> list = (ArrayList) values.get(key);
212
213                     for (Map<String, String> map : list) {
214                         OnapCommandParameter param = new OnapCommandParameter();
215
216                         for (Map.Entry<String, String> entry1 : map.entrySet()) {
217                             String key2 = entry1.getKey();
218
219                             if (Constants.NAME.equals(key2)) {
220                                 if (names.contains(map.get(key2))) {
221                                     throw new OnapCommandParameterNameConflict(map.get(key2));
222                                 }
223                                 names.add(map.get(key2));
224                                 param.setName(map.get(key2));
225                             } else if (Constants.DESCRIPTION.equals(key2)) {
226                                 param.setDescription(map.get(key2));
227                             } else if (Constants.SHORT_OPTION.equals(key2)) {
228                                 if (shortOptions.contains(map.get(key2))) {
229                                     throw new OnapCommandParameterOptionConflict(map.get(key2));
230                                 }
231                                 shortOptions.add(map.get(key2));
232                                 param.setShortOption(map.get(key2));
233                             } else if (Constants.LONG_OPTION.equals(key2)) {
234                                 if (longOptions.contains(map.get(key2))) {
235                                     throw new OnapCommandParameterOptionConflict(map.get(key2));
236                                 }
237                                 longOptions.add(map.get(key2));
238                                 param.setLongOption(map.get(key2));
239                             } else if (Constants.DEFAULT_VALUE.equals(key2)) {
240                                 Object obj = map.get(key2);
241                                 param.setDefaultValue(obj.toString());
242                             } else if (Constants.TYPE.equals(key2)) {
243                                 param.setParameterType(ParameterType.get(map.get(key2)));
244                             } else if (Constants.IS_OPTIONAL.equals(key2)) {
245                                 if ("true".equalsIgnoreCase(String.valueOf(map.get(key2)))) {
246                                     param.setOptional(true);
247                                 } else {
248                                     param.setOptional(false);
249                                 }
250                             } else if (Constants.IS_SECURED.equals(key2)) {
251                                 if ("true".equalsIgnoreCase(String.valueOf(map.get(key2)))) {
252                                     param.setSecured(true);
253                                 } else {
254                                     param.setSecured(false);
255                                 }
256                             }
257                         }
258                         cmd.getParameters().add(param);
259
260                     }
261                 } else if (Constants.RESULTS.equals(key)) {
262                     Map<String, ?> valueMap = (Map<String, ?>) values.get(key);
263                     OnapCommandResult result = new OnapCommandResult();
264                     for (Map.Entry<String, ?> entry1 : valueMap.entrySet()) {
265                         String key3 = entry1.getKey();
266
267                         if (Constants.DIRECTION.equals(key3)) {
268                             result.setPrintDirection(PrintDirection.get((String) valueMap.get(key3)));
269                         } else if (Constants.ATTRIBUTES.equals(key3)) {
270                             List<Map<String, String>> attrs = (ArrayList) valueMap.get(key3);
271
272                             for (Map<String, String> map : attrs) {
273                                 OnapCommandResultAttribute attr = new OnapCommandResultAttribute();
274                                 for (Map.Entry<String, String> entry4 : map.entrySet()) {
275                                     String key4 = entry4.getKey();
276
277                                     if (Constants.NAME.equals(key4)) {
278                                         attr.setName(map.get(key4));
279                                     } else if (Constants.DESCRIPTION.equals(key4)) {
280                                         attr.setDescription(map.get(key4));
281                                     } else if (Constants.SCOPE.equals(key4)) {
282                                         attr.setScope(OnapCommandResultAttributeScope.get(map.get(key4)));
283                                     } else if (Constants.TYPE.equals(key4)) {
284                                         attr.setType(ParameterType.get(map.get(key4)));
285                                     } else if (Constants.IS_SECURED.equals(key4)) {
286                                         if ("true".equals(String.valueOf(map.get(key4)))) {
287                                             attr.setSecured(true);
288                                         } else {
289                                             attr.setSecured(false);
290                                         }
291                                     }
292
293                                 }
294                                 result.getRecords().add(attr);
295                             }
296                         }
297                     }
298                     cmd.setResult(result);
299                 }
300             }
301         } catch (OnapCommandException e) {
302             throw e;
303         } catch (Exception e) {
304             throw new OnapCommandInvalidSchema(schemaName, e);
305         }
306     }
307
308     /**
309      * Load the schema.
310      *
311      * @param cmd
312      *            OnapSwaggerBasedCommand
313      * @param schemaName
314      *            schema name
315      * @throws OnapCommandParameterNameConflict
316      *             param name conflict exception
317      * @throws OnapCommandParameterOptionConflict
318      *             param option conflict exception
319      * @throws OnapCommandInvalidParameterType
320      *             invalid param type exception
321      * @throws OnapCommandInvalidPrintDirection
322      *             invalid print direction exception
323      * @throws OnapCommandInvalidResultAttributeScope
324      *             invalid scope exception
325      * @throws OnapCommandSchemaNotFound
326      *             schema not found
327      * @throws OnapCommandInvalidSchema
328      *             invalid schema
329      * @throws OnapCommandInvalidSchemaVersion
330      *             invalid schema version
331      */
332     public static void loadSchema(OnapSwaggerCommand cmd, String schemaName) throws OnapCommandException {
333         try {
334             Map<String, ?> values = (Map<String, ?>) validateSchemaVersion(schemaName, cmd.getSchemaVersion());
335             Map<String, String> valueMap = (Map<String, String>) values.get(Constants.EXECUTOR);
336             OnapCommandExecutor exec = new OnapCommandExecutor();
337
338             for (Map.Entry<String, String> entry1 : valueMap.entrySet()) {
339                 String key1 = entry1.getKey();
340
341                 if (Constants.API.equals(key1)) {
342                     exec.setApi(valueMap.get(key1));
343                 } else if (Constants.CLIENT.equals(key1)) {
344                     exec.setClient(valueMap.get(key1));
345                 } else if (Constants.ENTITY.equals(key1)) {
346                     exec.setEntity(valueMap.get(key1));
347                 } else if (Constants.EXCEPTION.equals(key1)) {
348                     exec.setException(valueMap.get(key1));
349                 } else if (Constants.METHOD.equals(key1)) {
350                     exec.setMethod(valueMap.get(key1));
351                 }
352             }
353
354             cmd.setExecutor(exec);
355         } catch (OnapCommandException e) {
356             throw e;
357         } catch (Exception e) {
358             throw new OnapCommandInvalidSchema(schemaName, e);
359         }
360     }
361
362     /**
363      * Load the schema.
364      *
365      * @param cmd
366      *            OnapHttpCommand
367      * @param schemaName
368      *            schema name
369      * @throws OnapCommandParameterNameConflict
370      *             param name conflict exception
371      * @throws OnapCommandParameterOptionConflict
372      *             param option conflict exception
373      * @throws OnapCommandInvalidParameterType
374      *             invalid param type exception
375      * @throws OnapCommandInvalidPrintDirection
376      *             invalid print direction exception
377      * @throws OnapCommandInvalidResultAttributeScope
378      *             invalid scope exception
379      * @throws OnapCommandSchemaNotFound
380      *             schema not found
381      * @throws OnapCommandInvalidSchema
382      *             invalid schema
383      * @throws OnapCommandInvalidSchemaVersion
384      *             invalid schema version
385      */
386     public static void loadSchema(OnapHttpCommand cmd, String schemaName) throws OnapCommandException {
387         try {
388             Map<String, ?> values = (Map<String, ?>) validateSchemaVersion(schemaName, cmd.getSchemaVersion());
389             Map<String, ?> valMap = (Map<String, ?>) values.get(Constants.HTTP);
390
391             for (Map.Entry<String, ?> entry1 : valMap.entrySet()) {
392                 String key1 = entry1.getKey();
393                 if (Constants.REQUEST.equals(key1)) {
394                     Map<String, ?> map = (Map<String, ?>) valMap.get(key1);
395
396                     for (Map.Entry<String, ?> entry2 : map.entrySet()) {
397                         String key2 = entry2.getKey();
398
399                         if (Constants.URI.equals(key2)) {
400                             Object obj = map.get(key2);
401                             cmd.getInput().setUri(obj.toString());
402                         } else if (Constants.MERHOD.equals(key2)) {
403                             Object obj = map.get(key2);
404                             cmd.getInput().setMethod(obj.toString());
405                         } else if (Constants.BODY.equals(key2)) {
406                             Object obj = map.get(key2);
407                             cmd.getInput().setBody(obj.toString());
408                         } else if (Constants.HEADERS.equals(key2)) {
409                             Map<String, String> head = (Map<String, String>) map.get(key2);
410                             cmd.getInput().setReqHeaders(head);
411                         } else if (Constants.QUERIES.equals(key2)) {
412                             Map<String, String> query = (Map<String, String>) map.get(key2);
413
414                             cmd.getInput().setReqQueries(query);
415                         }
416                     }
417                 } else if (Constants.SUCCESS_CODES.equals(key1)) {
418                     cmd.setSuccessStatusCodes((ArrayList) valMap.get(key1));
419                 } else if (Constants.RESULT_MAP.equals(key1)) {
420                     cmd.setResultMap((Map<String, String>) valMap.get(key1));
421                 } else if (Constants.SAMPLE_RESPONSE.equals(key1)) {
422                     // (mrkanag) implement sample response handling
423                 }
424             }
425
426         } catch (OnapCommandException e) {
427             throw e;
428         } catch (Exception e) {
429             throw new OnapCommandInvalidSchema(schemaName, e);
430         }
431     }
432
433     /**
434      * Returns Help.
435      *
436      * @param cmd
437      *            OnapCommand
438      * @return help string
439      * @throws OnapCommandHelpFailed
440      *             help failed exception
441      */
442     public static String help(OnapCommand cmd) throws OnapCommandHelpFailed {
443         String help = "usage: onap " + cmd.getName();
444
445         // Add description
446         help += "\n\n" + cmd.getDescription();
447
448         // Add service
449         help += "\n\nOnap service: " + cmd.getService();
450
451         // Add whole command
452         String commandOptions = "";
453
454         // Add parameters
455         OnapCommandResult paramTable = new OnapCommandResult();
456         paramTable.setPrintDirection(PrintDirection.LANDSCAPE);
457         paramTable.setType(ResultType.TABLE);
458         paramTable.setIncludeTitle(false);
459         paramTable.setIncludeSeparator(false);
460
461         OnapCommandResultAttribute attrName = new OnapCommandResultAttribute();
462         attrName.setName(Constants.NAME);
463         attrName.setDescription(Constants.NAME);
464         attrName.setScope(OnapCommandResultAttributeScope.SHORT);
465         paramTable.getRecords().add(attrName);
466
467         OnapCommandResultAttribute attrDescription = new OnapCommandResultAttribute();
468         attrDescription.setName(Constants.DESCRIPTION);
469         attrDescription.setDescription(Constants.DESCRIPTION);
470         attrDescription.setScope(OnapCommandResultAttributeScope.SHORT);
471         paramTable.getRecords().add(attrDescription);
472
473         int newLineOptions = 0;
474         for (OnapCommandParameter param : cmd.getParameters()) {
475             // First column Option or positional args
476             String optFirstCol;
477             if (newLineOptions == 3) {
478                 newLineOptions = 0;
479                 commandOptions += "\n";
480             }
481
482             if (param.getShortOption() != null || param.getLongOption() != null) {
483                 optFirstCol = OnapCommandParameter.printShortOption(param.getShortOption()) + " | "
484                         + OnapCommandParameter.printLongOption(param.getLongOption());
485                 commandOptions += "[" + optFirstCol + "] ";
486             } else {
487                 optFirstCol = param.getName();
488                 commandOptions += "<" + optFirstCol + "> ";
489             }
490
491             newLineOptions++;
492
493             attrName.getValues().add(optFirstCol);
494
495             // Second column description
496             String optSecondCol = param.getDescription().trim();
497             if (!optSecondCol.endsWith(".")) {
498                 optSecondCol += ".";
499             }
500             optSecondCol += " It is of type " + param.getParameterType().name() + ".";
501
502             if (param.getParameterType().equals(ParameterType.JSON)
503                     || param.getParameterType().equals(ParameterType.YAML)) {
504                 optSecondCol += " It's recommended to input the complete path of the file, which is having the value for it.";
505             }
506             if (param.isOptional()) {
507                 optSecondCol += " It is optional.";
508             }
509
510             String defaultMsg = " By default, it is ";
511             if (param.isDefaultValueAnEnv()) {
512                 optSecondCol += defaultMsg + "read from environment variable " + param.getEnvVarNameFromDefaultValue()
513                         + ".";
514             } else if (param.getDefaultValue() != null && !param.getDefaultValue().isEmpty()) {
515                 optSecondCol += defaultMsg + param.getDefaultValue() + ".";
516             }
517
518             if (param.isSecured()) {
519                 optSecondCol += " Secured.";
520             }
521             // (mrkanag) Add help msg for reading default value from env
522             attrDescription.getValues().add(optSecondCol);
523         }
524
525         try {
526             help += "\n\nOptions:\n" + commandOptions + "\nwhere,\n" + paramTable.print();
527         } catch (OnapCommandException e) {
528             throw new OnapCommandHelpFailed(e);
529         }
530
531         // Add results
532         OnapCommandResult resultTable = new OnapCommandResult();
533         resultTable.setPrintDirection(PrintDirection.PORTRAIT);
534         resultTable.setType(ResultType.TABLE);
535         resultTable.setIncludeTitle(false);
536         resultTable.setIncludeSeparator(false);
537
538         for (OnapCommandResultAttribute attr : cmd.getResult().getRecords()) {
539             OnapCommandResultAttribute attrHelp = new OnapCommandResultAttribute();
540             attrHelp.setName(attr.getName());
541             attrHelp.setDescription(attr.getDescription());
542             String msg = attr.getDescription() + " and is of type " + attr.getType().name() + ".";
543             if (attr.isSecured()) {
544                 msg += " It is secured.";
545             }
546             attrHelp.getValues().add(msg);
547             attrHelp.setType(attr.getType());
548             resultTable.getRecords().add(attrHelp);
549         }
550         try {
551             help += "\n\nResults:\n" + resultTable.print();
552         } catch (OnapCommandException e) {
553             throw new OnapCommandHelpFailed(e);
554         }
555
556         // Error
557         help += "\n\nError:\nOn error, it prints <HTTP STATUS CODE>::<ERROR CODE>::<ERROR MESSAGE>\n";
558         return help;
559     }
560
561     /**
562      * Helps to create OnapCredentials from default params.
563      *
564      * @param params
565      *            list of parameters
566      * @return OnapCredentials
567      * @throws OnapCommandInvalidParameterValue
568      *             exception
569      */
570     public static OnapCredentials fromParameters(List<OnapCommandParameter> params)
571             throws OnapCommandInvalidParameterValue {
572         Map<String, String> paramMap = new HashMap<>();
573
574         for (OnapCommandParameter param : params) {
575             paramMap.put(param.getName(), param.getValue().toString());
576         }
577
578         return new OnapCredentials(paramMap.get(Constants.DEAFULT_PARAMETER_USERNAME),
579                 paramMap.get(Constants.DEAFULT_PARAMETER_PASS_WORD),
580                 paramMap.get(Constants.DEAFULT_PARAMETER_MSB_URL));
581     }
582
583     /**
584      * Create Dict from list of Parameters.
585      *
586      * @param inputs
587      *            list of parameters
588      * @return map
589      */
590     public static Map<String, OnapCommandParameter> getInputMap(List<OnapCommandParameter> inputs) {
591         Map<String, OnapCommandParameter> map = new HashMap<>();
592         for (OnapCommandParameter param : inputs) {
593             map.put(param.getName(), param);
594         }
595         return map;
596     }
597
598     /**
599      * Discover the Onap commands.
600      *
601      * @return list
602      */
603     public static List<Class<OnapCommand>> findOnapCommands() {
604         ServiceLoader<OnapCommand> loader = ServiceLoader.load(OnapCommand.class);
605         List<Class<OnapCommand>> clss = new ArrayList<>();
606         for (OnapCommand implClass : loader) {
607             clss.add((Class<OnapCommand>) implClass.getClass());
608         }
609
610         return clss;
611     }
612
613     /**
614      * sort the set.
615      *
616      * @param col
617      *            set
618      * @return list
619      */
620     public static List<String> sort(Set<String> col) {
621         List<String> results = new ArrayList<>();
622         results.addAll(col);
623         Collections.sort(results);
624         return results;
625     }
626
627     /**
628      * Flatten the json list.
629      *
630      * @param jsons
631      *            list json strings
632      * @return list
633      */
634     public static List<String> jsonFlatten(List<String> jsons) {
635         List<String> results = new ArrayList<>();
636         for (String json : jsons) {
637             try {
638                 results.add(JsonPath.parse(json).jsonString());
639             } catch (Exception e) { // NOSONAR
640                 results.add(json);
641             }
642         }
643
644         return results;
645     }
646
647     /**
648      * Construct method name.
649      *
650      * @param name
651      *            name
652      * @param prefix
653      *            prefix
654      * @return string
655      */
656     public static String formMethodNameFromAttributeName(String name, String prefix) {
657         if (name == null || name.isEmpty()) {
658             return name;
659         }
660
661         String methodName = prefix;
662         for (String tk : name.split("-")) {
663             methodName += Character.toString(tk.charAt(0)).toUpperCase();
664             methodName += tk.substring(1);
665         }
666         return methodName;
667     }
668
669     private static String replaceLineFromInputParameters(String line, Map<String, OnapCommandParameter> params)
670             throws OnapCommandException {
671         String result = "";
672
673         if (!line.contains("${")) {
674             return line;
675         }
676
677         int currentIdx = 0;
678         while (currentIdx < line.length()) {
679             int idxS = line.indexOf("${", currentIdx);
680             if (idxS == -1) {
681                 result += line.substring(currentIdx);
682                 break;
683             }
684             int idxE = line.indexOf("}", idxS);
685             String paramName = line.substring(idxS + 2, idxE);
686             paramName = paramName.trim();
687             if (!params.containsKey(paramName)) {
688                 throw new OnapCommandParameterNotFound(paramName);
689             }
690
691             String value = params.get(paramName).getValue().toString();
692
693             OnapCommandParameter param = params.get(paramName);
694             if (ParameterType.ARRAY.equals(param.getParameterType())
695                     || ParameterType.MAP.equals(param.getParameterType())
696                     || ParameterType.JSON.equals(param.getParameterType())
697                     || ParameterType.YAML.equals(param.getParameterType())) {
698                 // ignore the front and back double quotes in json body
699                 result += line.substring(currentIdx, idxS - 1) + value;
700                 currentIdx = idxE + 2;
701             } else {
702                 result += line.substring(currentIdx, idxS) + value;
703                 currentIdx = idxE + 1;
704             }
705         }
706
707         return result;
708     }
709
710     private static ArrayList<String> replaceLineFromOutputResults(String line, HttpResult resultHttp)
711             throws OnapCommandHttpHeaderNotFound, OnapCommandHttpInvalidResponseBody,
712             OnapCommandResultMapProcessingFailed, OnapCommandResultEmpty {
713         String headerProcessedLine = "";
714
715         ArrayList<String> result = new ArrayList<>();
716         if (!line.contains("$b{") && !line.contains("$h{")) {
717             result.add(line);
718             return result;
719         }
720
721         /**
722          * In case of empty response body [] or {}
723          **/
724         if (resultHttp.getBody().length() <= 2) {
725             return result;
726         }
727
728         /**
729          * Process headers macros : line: $h{abc}-$b{$.[*].xyz} , After processing line will be [abc's
730          * value]-$b{$.[*].xyz}
731          **/
732         int currentIdx = 0;
733         while (currentIdx < line.length()) {
734             int idxS = line.indexOf("$h{", currentIdx);
735             if (idxS == -1) {
736                 headerProcessedLine += line.substring(currentIdx);
737                 break;
738             }
739             int idxE = line.indexOf("}", idxS);
740             String headerName = line.substring(idxS + 3, idxE);
741             headerName = headerName.trim();
742             if (!resultHttp.getRespHeaders().containsKey(headerName)) {
743                 throw new OnapCommandHttpHeaderNotFound(headerName);
744             }
745             String value = resultHttp.getRespHeaders().get(headerName);
746
747             headerProcessedLine += line.substring(currentIdx, idxS) + value;
748             currentIdx = idxE + 1;
749         }
750
751         // Process body jsonpath macros
752         List<Object> values = new ArrayList<>();
753         String bodyProcessedPattern = "";
754         currentIdx = 0;
755         int maxRows = 1; // in normal case, only one row will be there
756         while (currentIdx < headerProcessedLine.length()) {
757             int idxS = headerProcessedLine.indexOf("$b{", currentIdx);
758             if (idxS == -1) {
759                 bodyProcessedPattern += headerProcessedLine.substring(currentIdx);
760                 break;
761             }
762             int idxE = headerProcessedLine.indexOf("}", idxS);
763             String jsonPath = headerProcessedLine.substring(idxS + 3, idxE);
764             jsonPath = jsonPath.trim();
765             try {
766                 // JSONArray or String
767                 Object value = JsonPath.read(resultHttp.getBody(), jsonPath);
768                 if (value instanceof JSONArray) {
769                     JSONArray arr = (JSONArray) value;
770                     if (arr.size() > maxRows) {
771                         maxRows = arr.size();
772                     }
773                 }
774                 bodyProcessedPattern += headerProcessedLine.substring(currentIdx, idxS) + "%s";
775                 values.add(value);
776                 currentIdx = idxE + 1;
777             } catch (Exception e) {
778                 throw new OnapCommandHttpInvalidResponseBody(jsonPath, e);
779             }
780         }
781
782         if (bodyProcessedPattern.isEmpty()) {
783             result.add(headerProcessedLine);
784             return result;
785         } else {
786             for (int i = 0; i < maxRows; i++) {
787                 currentIdx = 0;
788                 String bodyProcessedLine = "";
789                 int positionalIdx = 0; // %s positional idx
790                 while (currentIdx < bodyProcessedPattern.length()) {
791                     int idxS = bodyProcessedPattern.indexOf("%s", currentIdx);
792                     if (idxS == -1) {
793                         bodyProcessedLine += bodyProcessedPattern.substring(currentIdx);
794                         break;
795                     }
796                     int idxE = idxS + 2; // %s
797                     try {
798                         Object value = values.get(positionalIdx);
799                         String valueS = String.valueOf(value);
800                         if (value instanceof JSONArray) {
801                             JSONArray arr = (JSONArray) value;
802                             if (!arr.isEmpty()) {
803                                 valueS = arr.get(i).toString();
804                             } else {
805                                 throw new OnapCommandResultEmpty();
806                             }
807                         }
808
809                         bodyProcessedLine += bodyProcessedPattern.substring(currentIdx, idxS) + valueS;
810                         currentIdx = idxE;
811                         positionalIdx++;
812                     } catch (OnapCommandResultEmpty e) {
813                         throw e;
814                     } catch (Exception e) {
815                         throw new OnapCommandResultMapProcessingFailed(line, e);
816                     }
817                 }
818                 result.add(bodyProcessedLine);
819             }
820
821             return result;
822         }
823     }
824
825     /**
826      * Set argument to param value.
827      *
828      * @param params
829      *            map
830      * @param input
831      *            HttpInput
832      * @return HttpInput
833      * @throws OnapCommandParameterNotFound
834      *             exception
835      * @throws OnapCommandInvalidParameterValue
836      *             exception
837      */
838     public static HttpInput populateParameters(Map<String, OnapCommandParameter> params, HttpInput input)
839             throws OnapCommandException {
840         HttpInput inp = new HttpInput();
841         for (OnapCommandParameter param : params.values()) {
842             if (ParameterType.BINARY.equals(param.getParameterType())) {
843                 inp.setBinaryData(true);
844                 break;
845             }
846         }
847         inp.setBody(replaceLineFromInputParameters(input.getBody(), params));
848         inp.setUri(replaceLineFromInputParameters(input.getUri(), params));
849         inp.setMethod(input.getMethod().toLowerCase());
850         for (String h : input.getReqHeaders().keySet()) {
851             String value = input.getReqHeaders().get(h);
852             inp.getReqHeaders().put(h, replaceLineFromInputParameters(value, params));
853         }
854
855         for (String h : input.getReqQueries().keySet()) {
856             String value = input.getReqQueries().get(h);
857             inp.getReqQueries().put(h, replaceLineFromInputParameters(value, params));
858         }
859
860         return inp;
861     }
862
863     /**
864      * Populate result.
865      *
866      * @param resultMap
867      *            map
868      * @param resultHttp
869      *            HttpResult
870      * @return map
871      * @throws OnapCommandHttpHeaderNotFound
872      *             header not found exception
873      * @throws OnapCommandHttpInvalidResponseBody
874      *             invalid response body exception
875      * @throws OnapCommandResultMapProcessingFailed
876      *             map processing failed exception
877      */
878     public static Map<String, ArrayList<String>> populateOutputs(Map<String, String> resultMap, HttpResult resultHttp)
879             throws OnapCommandException {
880         Map<String, ArrayList<String>> resultsProcessed = new HashMap<>();
881
882         for (Entry<String, String> entry : resultMap.entrySet()) {
883             String key = entry.getKey();
884             resultsProcessed.put(key, replaceLineFromOutputResults(resultMap.get(key), resultHttp));
885         }
886
887         return resultsProcessed;
888     }
889
890     /**
891      * Find external schema files.
892      *
893      * @return list ExternalSchema
894      * @throws OnapCommandDiscoveryFailed
895      *             exception
896      * @throws OnapCommandInvalidSchema
897      *             exception
898      */
899     public static List<ExternalSchema> findAllExternalSchemas() throws OnapCommandException {
900         List<ExternalSchema> extSchemas = new ArrayList<>();
901         try {
902             Resource[] res = getExternalResources(Constants.EXTERNAL_SCHEMA_PATH_PATERN);
903             if (res != null && res.length > 0) {
904                 Map<String, ?> resourceMap;
905                 for (Resource resource : res) {
906                     resourceMap = getExternalSchemaMap(resource);
907                     if (resourceMap != null && resourceMap.size() > 0) {
908                         ExternalSchema schema = new ExternalSchema();
909                         schema.setSchemaName(resource.getFilename());
910                         schema.setCmdName((String) resourceMap.get(Constants.NAME));
911                         Object obj = resourceMap.get(Constants.ONAP_CMD_SCHEMA_VERSION);
912                         schema.setVersion(obj.toString());
913                         extSchemas.add(schema);
914                     }
915                 }
916             }
917         } catch (IOException e) {
918             throw new OnapCommandDiscoveryFailed(Constants.EXTERNAL_SCHEMA_DIRECTORY, e);
919         }
920
921         return extSchemas;
922     }
923
924     /**
925      * Returns all resources available under certain directory in class-path.
926      *
927      * @param pattern
928      *            search pattern
929      * @return resources found resources
930      * @throws IOException
931      *             exception
932      */
933     public static Resource[] getExternalResources(String pattern) throws IOException {
934         ClassLoader cl = OnapCommandUtils.class.getClassLoader();
935         ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(cl);
936         return resolver.getResources("classpath*:" + pattern);
937     }
938
939     /**
940      * Returns a resource available under certain directory in class-path.
941      *
942      * @param pattern
943      *            search pattern
944      * @return found resource
945      * @throws IOException
946      *             exception
947      */
948     public static Resource getExternalResource(String fileName, String pattern) throws IOException {
949         Resource[] resources = getExternalResources(pattern);
950         if (resources != null && resources.length > 0) {
951             for (Resource res : resources) {
952                 if (res.getFilename().equals(fileName)) {
953                     return res;
954                 }
955             }
956         }
957
958         return null;
959     }
960
961     /**
962      * Get schema map.
963      *
964      * @param resource
965      *            resource obj
966      * @return map
967      * @throws OnapCommandInvalidSchema
968      *             exception
969      */
970     public static Map<String, ?> getExternalSchemaMap(Resource resource) throws OnapCommandInvalidSchema {
971         Map<String, ?> values = null;
972         try {
973             values = (Map<String, ?>) new Yaml().load(resource.getInputStream());
974         } catch (Exception e) {
975             throw new OnapCommandInvalidSchema(resource.getFilename(), e);
976         }
977         return values;
978     }
979
980     /**
981      * Persist the external schema details.
982      *
983      * @param schemas
984      *            list
985      * @throws OnapCommandDiscoveryFailed
986      *             exception
987      */
988     public static void persist(List<ExternalSchema> schemas) throws OnapCommandDiscoveryFailed {
989         if (schemas != null) {
990             try {
991                 Resource[] resources = getExternalResources(Constants.EXTERNAL_DISCOVERY_DIRECTORY);
992                 if (resources != null && resources.length == 1) {
993                     String path = resources[0].getURI().getPath();
994                     File file = new File(path + File.separator + Constants.EXTERNAL_DISCOVERY_FILE);
995                     ObjectMapper mapper = new ObjectMapper();
996                     mapper.writerWithDefaultPrettyPrinter().writeValue(file, schemas);
997                 }
998             } catch (IOException e1) {
999                 throw new OnapCommandDiscoveryFailed(Constants.EXTERNAL_DISCOVERY_DIRECTORY,
1000                         Constants.EXTERNAL_DISCOVERY_FILE, e1);
1001             }
1002         }
1003     }
1004
1005     /**
1006      * Check if json file discovered or not.
1007      *
1008      * @return boolean
1009      * @throws OnapCommandDiscoveryFailed
1010      *             exception
1011      */
1012     public static boolean isJsonFileDiscovered() throws OnapCommandDiscoveryFailed {
1013         Resource resource = null;
1014         try {
1015             resource = getExternalResource(Constants.EXTERNAL_DISCOVERY_FILE,
1016                     Constants.EXTERNAL_DISCOVERY_DIRECTORY_PATTERN);
1017             if (resource != null) {
1018                 return true;
1019             }
1020         } catch (IOException e) {
1021             throw new OnapCommandDiscoveryFailed(Constants.EXTERNAL_DISCOVERY_DIRECTORY,
1022                     Constants.EXTERNAL_DISCOVERY_FILE, e);
1023         }
1024
1025         return false;
1026     }
1027
1028     /**
1029      * Load the previous discovered json file.
1030      *
1031      * @return list
1032      * @throws OnapCommandInvalidSchema
1033      *             exception
1034      * @throws OnapCommandDiscoveryFailed
1035      *             exception
1036      */
1037     public static List<ExternalSchema> loadExternalSchemasFromJson() throws OnapCommandException {
1038         List<ExternalSchema> schemas = new ArrayList<>();
1039         if (!isJsonFileDiscovered()) {
1040             schemas = findAllExternalSchemas();
1041             if (!schemas.isEmpty()) {
1042                 persist(schemas);
1043             }
1044         } else {
1045             try {
1046                 Resource resource = getExternalResource(Constants.EXTERNAL_DISCOVERY_FILE,
1047                         Constants.EXTERNAL_DISCOVERY_DIRECTORY_PATTERN);
1048                 if (resource != null) {
1049                     File file = new File(resource.getURI().getPath());
1050                     ObjectMapper mapper = new ObjectMapper();
1051                     ExternalSchema[] list = mapper.readValue(file, ExternalSchema[].class);
1052                     schemas.addAll(Arrays.asList(list));
1053                 }
1054             } catch (IOException e) {
1055                 throw new OnapCommandDiscoveryFailed(Constants.EXTERNAL_DISCOVERY_DIRECTORY,
1056                         Constants.EXTERNAL_DISCOVERY_FILE, e);
1057             }
1058         }
1059
1060         return schemas;
1061     }
1062
1063     /**
1064      * Fetch a particular schema details.
1065      *
1066      * @param cmd
1067      *            command name
1068      * @return ExternalSchema obj
1069      * @throws OnapCommandInvalidSchema
1070      *             exception
1071      * @throws OnapCommandDiscoveryFailed
1072      *             exception
1073      */
1074     public static ExternalSchema loadExternalSchemaFromJson(String cmd) throws OnapCommandException {
1075         List<ExternalSchema> list = loadExternalSchemasFromJson();
1076         ExternalSchema schemaStr = null;
1077         if (list != null) {
1078             for (ExternalSchema schema : list) {
1079                 if (cmd.equals(schema.getCmdName())) {
1080                     schemaStr = schema;
1081                     break;
1082                 }
1083             }
1084         }
1085         return schemaStr;
1086     }
1087 }