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