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