mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Gaetan Boismal
27.02.2015 0fd845d18cfaf23fc9f54e92775c735955e4e859
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
 * or http://forgerock.org/license/CDDLv1.0.html.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at legal-notices/CDDLv1_0.txt.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 *      Portions Copyright 2014-2015 ForgeRock AS
 */
package com.forgerock.opendj.cli;
 
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
 
import org.forgerock.i18n.LocalizableMessage;
 
/**
 * A class which can be used to construct tables of information to be displayed in a terminal.
 * Once built the table can be output using a {@link TableSerializer}.
 */
public final class TableBuilder {
 
    /**
     * The current column number in the current row where 0 represents
     * the left-most column in the table.
     */
    private int column;
 
    /** The current with of each column. */
    private List<Integer> columnWidths = new ArrayList<>();
 
    /** The list of column headings. */
    private List<LocalizableMessage> header = new ArrayList<>();
 
    /** The current number of rows in the table. */
    private int height;
 
    /** The list of table rows. */
    private List<List<String>> rows = new ArrayList<>();
 
    /** The linked list of sort keys comparators. */
    private List<Comparator<String>> sortComparators = new ArrayList<>();
 
    /** The linked list of sort keys. */
    private List<Integer> sortKeys = new ArrayList<>();
 
    /** The current number of columns in the table. */
    private int width;
 
    /**
     * Creates a new table printer.
     */
    public TableBuilder() {
        // No implementation required.
    }
 
    /**
     * Adds a table sort key. The table will be sorted according to the case-insensitive string ordering of the cells in
     * the specified column.
     *
     * @param column
     *            The column which will be used as a sort key.
     */
    public void addSortKey(int column) {
        addSortKey(column, String.CASE_INSENSITIVE_ORDER);
    }
 
    /**
     * Adds a table sort key. The table will be sorted according to the provided string comparator.
     *
     * @param column
     *            The column which will be used as a sort key.
     * @param comparator
     *            The string comparator.
     */
    public void addSortKey(int column, Comparator<String> comparator) {
        sortKeys.add(column);
        sortComparators.add(comparator);
    }
 
    /**
     * Appends a new blank cell to the current row.
     */
    public void appendCell() {
        appendCell("");
    }
 
    /**
     * Appends a new cell to the current row containing the provided boolean value.
     *
     * @param value
     *            The boolean value.
     */
    public void appendCell(boolean value) {
        appendCell(String.valueOf(value));
    }
 
    /**
     * Appends a new cell to the current row containing the provided byte value.
     *
     * @param value
     *            The byte value.
     */
    public void appendCell(byte value) {
        appendCell(String.valueOf(value));
    }
 
    /**
     * Appends a new cell to the current row containing the provided char value.
     *
     * @param value
     *            The char value.
     */
    public void appendCell(char value) {
        appendCell(String.valueOf(value));
    }
 
    /**
     * Appends a new cell to the current row containing the provided double value.
     *
     * @param value
     *            The double value.
     */
    public void appendCell(double value) {
        appendCell(String.valueOf(value));
    }
 
    /**
     * Appends a new cell to the current row containing the provided float value.
     *
     * @param value
     *            The float value.
     */
    public void appendCell(float value) {
        appendCell(String.valueOf(value));
    }
 
    /**
     * Appends a new cell to the current row containing the provided integer value.
     *
     * @param value
     *            The boolean value.
     */
    public void appendCell(int value) {
        appendCell(String.valueOf(value));
    }
 
    /**
     * Appends a new cell to the current row containing the provided long value.
     *
     * @param value
     *            The long value.
     */
    public void appendCell(long value) {
        appendCell(String.valueOf(value));
    }
 
    /**
     * Appends a new cell to the current row containing the provided object value.
     *
     * @param value
     *            The object value.
     */
    public void appendCell(Object value) {
        // Make sure that the first row has been created.
        if (height == 0) {
            startRow();
        }
 
        // Create the cell.
        String s = String.valueOf(value);
        rows.get(height - 1).add(s);
        column++;
 
        // Update statistics.
        if (column > width) {
            width = column;
            columnWidths.add(s.length());
        } else if (columnWidths.get(column - 1) < s.length()) {
            columnWidths.set(column - 1, s.length());
        }
    }
 
    /**
     * Appends a new blank column heading to the header row.
     */
    public void appendHeading() {
        appendHeading(LocalizableMessage.EMPTY);
    }
 
    /**
     * Appends a new column heading to the header row.
     *
     * @param value
     *            The column heading value.
     */
    public void appendHeading(LocalizableMessage value) {
        header.add(value);
 
        // Update statistics.
        if (header.size() > width) {
            width = header.size();
            columnWidths.add(value.length());
        } else if (columnWidths.get(header.size() - 1) < value.length()) {
            columnWidths.set(header.size() - 1, value.length());
        }
    }
 
    /**
     * Gets the width of the current row.
     *
     * @return Returns the width of the current row.
     */
    public int getRowWidth() {
        return column;
    }
 
    /**
     * Gets the number of rows in table.
     *
     * @return Returns the number of rows in table.
     */
    public int getTableHeight() {
        return height;
    }
 
    /**
     * Gets the number of columns in table.
     *
     * @return Returns the number of columns in table.
     */
    public int getTableWidth() {
        return width;
    }
 
    /**
     * Prints the table in its current state using the provided table printer.
     *
     * @param printer
     *            The table printer.
     */
    public void print(TablePrinter printer) {
        // Create a new printer instance.
        TableSerializer serializer = printer.getSerializer();
 
        // First sort the table.
        List<List<String>> sortedRows = new ArrayList<>(rows);
 
        Comparator<List<String>> comparator = new Comparator<List<String>>() {
 
            public int compare(List<String> row1, List<String> row2) {
                for (int i = 0; i < sortKeys.size(); i++) {
                    String cell1 = row1.get(sortKeys.get(i));
                    String cell2 = row2.get(sortKeys.get(i));
 
                    int rc = sortComparators.get(i).compare(cell1, cell2);
                    if (rc != 0) {
                        return rc;
                    }
                }
 
                // Both rows are equal.
                return 0;
            }
 
        };
 
        Collections.sort(sortedRows, comparator);
 
        // Now output the table.
        serializer.startTable(height, width);
        for (int i = 0; i < width; i++) {
            serializer.addColumn(columnWidths.get(i));
        }
 
        // Column headings.
        serializer.startHeader();
        for (LocalizableMessage s : header) {
            serializer.addHeading(s.toString());
        }
        serializer.endHeader();
 
        // Table contents.
        serializer.startContent();
        for (List<String> row : sortedRows) {
            serializer.startRow();
 
            // Print each cell in the row, padding missing trailing cells.
            for (int i = 0; i < width; i++) {
                if (i < row.size()) {
                    serializer.addCell(row.get(i));
                } else {
                    serializer.addCell("");
                }
            }
 
            serializer.endRow();
        }
        serializer.endContent();
        serializer.endTable();
    }
 
    /**
     * Appends a new row to the table.
     */
    public void startRow() {
        rows.add(new ArrayList<String>());
        height++;
        column = 0;
    }
}