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