-
Notifications
You must be signed in to change notification settings - Fork 511
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
HDDS-11268. [CLI] Improve CLI Display OM/SCM Roles.
- Loading branch information
Showing
3 changed files
with
321 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
277 changes: 277 additions & 0 deletions
277
hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/utils/FormattingCLIUtils.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,277 @@ | ||
/** | ||
* Licensed to the Apache Software Foundation (ASF) under one | ||
* or more contributor license agreements. See the NOTICE file | ||
* distributed with this work for additional information | ||
* regarding copyright ownership. The ASF licenses this file | ||
* to you under the Apache License, Version 2.0 (the | ||
* "License"); you may not use this file except in compliance | ||
* with the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package org.apache.hadoop.ozone.utils; | ||
|
||
import java.util.ArrayList; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
|
||
/** | ||
* The main core class that generates the ASCII TABLE. | ||
*/ | ||
public final class FormattingCLIUtils { | ||
/** Table title. */ | ||
private String title; | ||
/** Last processed row type. */ | ||
private TableRowType lastTableRowType; | ||
/** StringBuilder object used to concatenate strings. */ | ||
private StringBuilder join; | ||
/** An ordered Map that holds each row of data. */ | ||
private List<TableRow> tableRows; | ||
/** Maps the maximum length of each column. */ | ||
private Map<Integer, Integer> maxColMap; | ||
|
||
/** | ||
* Contains the title constructor. | ||
* @param title titleName | ||
*/ | ||
public FormattingCLIUtils(String title) { | ||
this.init(); | ||
this.title = title; | ||
} | ||
|
||
/** | ||
* Initialize the data. | ||
*/ | ||
private void init() { | ||
this.join = new StringBuilder(); | ||
this.tableRows = new ArrayList<>(); | ||
this.maxColMap = new HashMap<>(); | ||
} | ||
|
||
/** | ||
* Adds elements from the collection to the header data in the table. | ||
* @param headers Header data | ||
* @return FormattingCLIUtils object | ||
*/ | ||
public FormattingCLIUtils addHeaders(List<?> headers) { | ||
return this.appendRows(TableRowType.HEADER, headers.toArray()); | ||
} | ||
|
||
/** | ||
* Adds a row of normal data to the table. | ||
* @param objects Common row data | ||
* @return FormattingCLIUtils object | ||
*/ | ||
public FormattingCLIUtils addLine(Object... objects) { | ||
return this.appendRows(TableRowType.LINE, objects); | ||
} | ||
|
||
/** | ||
* Adds the middle row of data to the table. | ||
* @param tableRowType TableRowType | ||
* @param objects Table row data | ||
* @return FormattingCLIUtils object | ||
*/ | ||
private FormattingCLIUtils appendRows(TableRowType tableRowType, Object... objects) { | ||
if (objects != null && objects.length > 0) { | ||
int len = objects.length; | ||
if (this.maxColMap.size() > len) { | ||
throw new IllegalArgumentException("The number of columns that inserted a row " + | ||
"of data into the table is different from the number of previous columns, check!"); | ||
} | ||
List<String> lines = new ArrayList<>(); | ||
for (int i = 0; i < len; i++) { | ||
Object o = objects[i]; | ||
String value = o == null ? "null" : o.toString(); | ||
lines.add(value); | ||
Integer maxColSize = this.maxColMap.get(i); | ||
if (maxColSize == null) { | ||
this.maxColMap.put(i, value.length()); | ||
continue; | ||
} | ||
if (value.length() > maxColSize) { | ||
this.maxColMap.put(i, value.length()); | ||
} | ||
} | ||
this.tableRows.add(new TableRow(tableRowType, lines)); | ||
} | ||
return this; | ||
} | ||
|
||
/** | ||
* Builds the string for the row of the table title. | ||
*/ | ||
private void buildTitle() { | ||
if (this.title != null) { | ||
int maxTitleSize = 0; | ||
for (Integer maxColSize : this.maxColMap.values()) { | ||
maxTitleSize += maxColSize; | ||
} | ||
maxTitleSize += 3 * (this.maxColMap.size() - 1); | ||
if (this.title.length() > maxTitleSize) { | ||
this.title = this.title.substring(0, maxTitleSize); | ||
} | ||
this.join.append("+"); | ||
for (int i = 0; i < maxTitleSize + 2; i++) { | ||
this.join.append("-"); | ||
} | ||
this.join.append("+\n") | ||
.append("|") | ||
.append(StrUtils.center(this.title, maxTitleSize + 2, ' ')) | ||
.append("|\n"); | ||
this.lastTableRowType = TableRowType.TITLE; | ||
} | ||
} | ||
|
||
/** | ||
* Build the table, first build the title, and then walk through each row of data to build. | ||
*/ | ||
private void buildTable() { | ||
this.buildTitle(); | ||
for (int i = 0, len = this.tableRows.size(); i < len; i++) { | ||
List<String> data = this.tableRows.get(i).data; | ||
switch (this.tableRows.get(i).tableRowType) { | ||
case HEADER: | ||
if (this.lastTableRowType != TableRowType.HEADER) { | ||
this.buildRowBorder(data); | ||
} | ||
this.buildRowLine(data); | ||
this.buildRowBorder(data); | ||
break; | ||
case LINE: | ||
this.buildRowLine(data); | ||
if (i == len - 1) { | ||
this.buildRowBorder(data); | ||
} | ||
break; | ||
default: | ||
break; | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Method to build a border row. | ||
* @param data dataLine | ||
*/ | ||
private void buildRowBorder(List<String> data) { | ||
this.join.append("+"); | ||
for (int i = 0, len = data.size(); i < len; i++) { | ||
for (int j = 0; j < this.maxColMap.get(i) + 2; j++) { | ||
this.join.append("-"); | ||
} | ||
this.join.append("+"); | ||
} | ||
this.join.append("\n"); | ||
} | ||
|
||
/** | ||
* A way to build rows of data. | ||
* @param data dataLine | ||
*/ | ||
private void buildRowLine(List<String> data) { | ||
this.join.append("|"); | ||
for (int i = 0, len = data.size(); i < len; i++) { | ||
this.join.append(StrUtils.center(data.get(i), this.maxColMap.get(i) + 2, ' ')) | ||
.append("|"); | ||
} | ||
this.join.append("\n"); | ||
} | ||
|
||
/** | ||
* Rendering is born as a result. | ||
* @return ASCII string of Table | ||
*/ | ||
public String render() { | ||
this.buildTable(); | ||
return this.join.toString(); | ||
} | ||
|
||
/** | ||
* The type of each table row and the entity class of the data. | ||
*/ | ||
private static class TableRow { | ||
private TableRowType tableRowType; | ||
private List<String> data; | ||
TableRow(TableRowType tableRowType, List<String> data) { | ||
this.tableRowType = tableRowType; | ||
this.data = data; | ||
} | ||
} | ||
|
||
/** | ||
* An enumeration class that distinguishes between table headers and normal table data. | ||
*/ | ||
private enum TableRowType { | ||
TITLE, HEADER, LINE | ||
} | ||
|
||
/** | ||
* String utility class. | ||
*/ | ||
private static final class StrUtils { | ||
/** | ||
* Puts a string in the middle of a given size. | ||
* @param str Character string | ||
* @param size Total size | ||
* @param padChar Fill character | ||
* @return String result | ||
*/ | ||
private static String center(String str, int size, char padChar) { | ||
if (str != null && size > 0) { | ||
int strLen = str.length(); | ||
int pads = size - strLen; | ||
if (pads > 0) { | ||
str = leftPad(str, strLen + pads / 2, padChar); | ||
str = rightPad(str, size, padChar); | ||
} | ||
} | ||
return str; | ||
} | ||
|
||
/** | ||
* Left-fill the given string and size. | ||
* @param str String | ||
* @param size totalSize | ||
* @param padChar Fill character | ||
* @return String result | ||
*/ | ||
private static String leftPad(final String str, int size, char padChar) { | ||
int pads = size - str.length(); | ||
return pads <= 0 ? str : repeat(padChar, pads).concat(str); | ||
} | ||
|
||
/** | ||
* Right-fill the given string and size. | ||
* @param str String | ||
* @param size totalSize | ||
* @param padChar Fill character | ||
* @return String result | ||
*/ | ||
private static String rightPad(final String str, int size, char padChar) { | ||
int pads = size - str.length(); | ||
return pads <= 0 ? str : str.concat(repeat(padChar, pads)); | ||
} | ||
|
||
/** | ||
* Re-fill characters as strings. | ||
* @param ch String | ||
* @param repeat Number of repeats | ||
* @return String | ||
*/ | ||
private static String repeat(char ch, int repeat) { | ||
char[] buf = new char[repeat]; | ||
for (int i = repeat - 1; i >= 0; i--) { | ||
buf[i] = ch; | ||
} | ||
return new String(buf); | ||
} | ||
} | ||
} |