code improvements-sonar fixes
[cli.git] / framework / src / main / java / org / onap / cli / fw / output / print / OnapCommandPrint.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.output.print;
18
19 import java.io.IOException;
20 import java.io.StringWriter;
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.Collections;
24 import java.util.LinkedHashMap;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.StringTokenizer;
28
29 import org.apache.commons.csv.CSVFormat;
30 import org.apache.commons.csv.CSVPrinter;
31 import org.onap.cli.fw.error.OnapCommandOutputPrintingFailed;
32 import org.onap.cli.fw.output.OnapCommandPrintDirection;
33
34 import com.google.gson.JsonParser;
35
36 import net.minidev.json.JSONArray;
37 import net.minidev.json.JSONObject;
38 import net.minidev.json.JSONValue;
39 /**
40  * Oclip Command Table print.
41  *
42  */
43 public class OnapCommandPrint {
44
45
46     public static final int MAX_COLUMN_LENGTH = 50;
47
48     private OnapCommandPrintDirection direction;
49
50     private Map<String, List<String>> data = new LinkedHashMap<>();
51
52     private boolean printTitle = true;
53
54     public OnapCommandPrintDirection getDirection() {
55         return direction;
56     }
57
58     public void setDirection(OnapCommandPrintDirection direction) {
59         this.direction = direction;
60     }
61
62     public void addColumn(String header, List<String> data) {
63         this.data.put(header, data);
64     }
65
66     /**
67      * Get column.
68      *
69      * @param header
70      *            string
71      * @return list
72      */
73     public List<String> getColumn(String header) {
74         return this.data.computeIfAbsent(header, k -> new ArrayList<String>());
75     }
76
77     public boolean isPrintTitle() {
78         return printTitle;
79     }
80
81     public void setPrintTitle(boolean printTitle) {
82         this.printTitle = printTitle;
83     }
84
85     private int findMaxRows() {
86         int max = 1;
87         if (!this.isPrintTitle()) {
88             max = 0;
89         }
90         for (List<String> cols : this.data.values()) {
91             if (cols != null && max < cols.size()) {
92                 max = cols.size();
93             }
94         }
95
96         return max;
97     }
98
99     /**
100      * Helps to form the rows from columns.
101      *
102      * @param isNormalize
103      *            boolean
104      * @return +--------------+-----------+-----------------------------+ | header1 | header 2 | header 3 |
105      *         +--------------+-----------+-----------------------------+ | v1 | List[line| v 3 | | | 1, line2]| |
106      *         +--------------+-----------+-----------------------------+ | null | yyyyyy 2 | xxxxxx 3 |
107      *         +--------------+-----------+-----------------------------+
108      */
109     private List<List<Object>> formRows(boolean isNormalize) {
110         List<List<Object>> rows = new ArrayList<>();
111
112         // add title
113         if (this.isPrintTitle()) {
114             List<Object> list = new ArrayList<>();
115             for (String key : this.data.keySet()) {
116                 if (isNormalize && key != null && key.length() > MAX_COLUMN_LENGTH) {
117                     list.add(splitIntoList(key, MAX_COLUMN_LENGTH));
118                 } else {
119                     list.add(key);
120                 }
121             }
122             rows.add(list);
123         }
124
125         // form row
126         for (int i = 0; i < this.findMaxRows(); i++) {
127             List<Object> row = new ArrayList<>();
128             for (List<String> cols : this.data.values()) {
129                 if (cols != null && cols.size() > i) {
130                     String value = cols.get(i);
131                     // split the cell into multiple sub rows
132                     if (isNormalize && value != null && value.length() > MAX_COLUMN_LENGTH) {
133                         row.add(splitIntoList(value, MAX_COLUMN_LENGTH));
134                     } else {
135                         // store as string (one entry)
136                         row.add(value);
137                     }
138                 } else {
139                     // no value exist for this column
140                     row.add(null);
141                 }
142             }
143             rows.add(row);
144         }
145
146         return rows;
147     }
148
149     /**
150      * Splits big strings into list of strings based on maxCharInLine size.
151      *
152      * @param input
153      *            input string
154      * @param maxCharInLine
155      *            max length
156      * @return list of strings
157      */
158     public List<String> splitIntoList(String input, int maxCharInLine) {
159
160         String inp = input;
161
162         if (inp == null || "".equals(inp) || maxCharInLine <= 0) {
163             return Collections.emptyList();
164         }
165         // new line is converted to space char
166         if (inp.contains("\n")) {
167             inp = inp.replaceAll("\n", "");
168         }
169
170         StringTokenizer tok = new StringTokenizer(inp, " ");
171         StringBuilder output = new StringBuilder(inp.length());
172         int lineLen = 0;
173         while (tok.hasMoreTokens()) {
174             String word = tok.nextToken();
175
176             while (word.length() >= maxCharInLine) {
177                 output.append(word.substring(0, maxCharInLine - lineLen) + "\n");
178                 word = word.substring(maxCharInLine - lineLen);
179                 lineLen = 0;
180             }
181
182             if (lineLen + word.length() >= maxCharInLine) {
183                 output.append("\n");
184                 lineLen = 0;
185             }
186             output.append(word + " ");
187
188             lineLen += word.length() + 1;
189         }
190         String[] strArray = output.toString().split("\n");
191
192         return Arrays.asList(strArray);
193     }
194
195     /**
196      * Helps to print table.
197      *
198      * @param printSeparator
199      *            Prints with line separator
200      * @return +--------------+-----------+-----------------------------+ | header1 | header 2 | header 3 |
201      *         +--------------+-----------+-----------------------------+ | v1 | line 1 | v 3 | | | line 2 | |
202      *         +--------------+-----------+-----------------------------+ | | yyyyyy 2 | xxxxxx 3 |
203      *         +--------------+-----------+-----------------------------+
204      */
205     public String printTable(boolean printSeparator) {
206         List<List<Object>> rows = this.formRows(true);
207         TableGenerator table = new TableGenerator();
208         return table.generateTable(rows, printSeparator);
209     }
210
211     /**
212      * Print output in csv format.
213      *
214      * @return string
215      * @throws OnapCommandOutputPrintingFailed
216      *             exception
217      */
218     public String printCsv() throws OnapCommandOutputPrintingFailed {
219         CSVFormat formattor = CSVFormat.DEFAULT.withRecordSeparator(System.getProperty("line.separator"));
220
221         try (StringWriter writer = new StringWriter();
222              CSVPrinter printer = new CSVPrinter(writer, formattor);) {
223
224             List<List<Object>> rows = this.formRows(false);
225
226             for (int i = 0; i < this.findMaxRows(); i++) {
227                 printer.printRecord(rows.get(i));
228             }
229
230             return writer.toString();
231         } catch (IOException e) {
232             throw new OnapCommandOutputPrintingFailed(e);
233         }
234     }
235
236     public Object getJsonNodeOrString(String value) {
237         try {
238             return JSONValue.parse(value);
239         } catch (Exception e) {
240             return value;
241         }
242     }
243
244     public String printJson() {
245         List<List<Object>> rows = this.formRows(false);
246
247         if (this.direction.equals(OnapCommandPrintDirection.PORTRAIT)) {
248             JSONObject result = new JSONObject();
249             for (int i=1; i<rows.size(); i++) {
250                 if (rows.get(i).get(1) != null)
251                     result.put(rows.get(i).get(0).toString(), this.getJsonNodeOrString(rows.get(i).get(1).toString()));
252             }
253             return result.toJSONString();
254         } else {
255             JSONArray array = new JSONArray();
256
257             //skip first row title
258             List<Object> titleRow = rows.get(0);
259
260             for (int i=1; i<rows.size(); i++) {
261                 JSONObject rowO = new JSONObject();
262
263                 for (int j=0; j<titleRow.size(); j++) {
264                     if (rows.get(i).get(j) != null)
265                         rowO.put(titleRow.get(j).toString(), this.getJsonNodeOrString(rows.get(i).get(j).toString()));
266                 }
267
268                 array.add(rowO);
269             }
270             try {
271                 return new JsonParser().parse(array.toJSONString()).toString();
272             } catch (Exception e) { // NOSONAR
273                 // TODO Auto-generated catch block
274                 return array.toJSONString();
275             }
276
277         }
278     }
279
280     /*
281         required vulnerable fix
282         jackson-dataformat-yaml:YAMLMapper is a sub component of jackson-databind
283         jackson-databind is replaced with gson
284         JIRA: CLI-251
285      */
286     public String printYaml() throws OnapCommandOutputPrintingFailed {
287      /*   try {
288             return new YAMLMapper().writeValueAsString(new ObjectMapper().readTree(this.printJson()));
289         } catch (IOException  e) {
290             throw new OnapCommandOutputPrintingFailed(e);  // NOSONAR
291         }
292      */
293      return ""; //NOSONAR
294     }
295 }