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