SHL-126 - Add utility classes for rendering ascii based tables
This commit is contained in:
@@ -30,6 +30,7 @@ dependencies {
|
||||
compile "org.springframework:spring-core:$springVersion"
|
||||
compile "org.springframework:spring-context-support:$springVersion"
|
||||
compile "commons-io:commons-io:$commonsioVersion"
|
||||
compile "com.google.guava:guava:15.0"
|
||||
compile "jline:jline:$jlineVersion"
|
||||
compile "cglib:cglib:$cglibVersion"
|
||||
|
||||
|
||||
130
src/main/java/org/springframework/shell/support/table/Table.java
Normal file
130
src/main/java/org/springframework/shell/support/table/Table.java
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright 2009-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.shell.support.table;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* Provide a basic concept of a table structure containing a map of column
|
||||
* headers and a collection of rows. Used to render text-based tables (console
|
||||
* output).
|
||||
*
|
||||
* @see TableRenderer
|
||||
*
|
||||
* @author Gunnar Hillert
|
||||
*
|
||||
*/
|
||||
public class Table {
|
||||
|
||||
private final Map<Integer, TableHeader> headers = new TreeMap<Integer, TableHeader>();
|
||||
|
||||
private volatile List<TableRow> rows = new ArrayList<TableRow>(0);
|
||||
|
||||
public List<TableRow> getRows() {
|
||||
return rows;
|
||||
}
|
||||
|
||||
public Map<Integer, TableHeader> getHeaders() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
public Table addHeader(Integer columnIndex, TableHeader tableHeader) {
|
||||
this.headers.put(columnIndex, tableHeader);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new empty row to the table.
|
||||
*
|
||||
* @return the newly created row, which can be then be populated
|
||||
*/
|
||||
public TableRow newRow() {
|
||||
TableRow row = new TableRow();
|
||||
rows.add(row);
|
||||
return row;
|
||||
}
|
||||
|
||||
public Table addRow(String... values) {
|
||||
|
||||
final TableRow row = new TableRow();
|
||||
|
||||
int column = 1;
|
||||
|
||||
for (String value : values) {
|
||||
row.addValue(column, value);
|
||||
column++;
|
||||
}
|
||||
|
||||
rows.add(row);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public void calculateColumnWidths() {
|
||||
for (java.util.Map.Entry<Integer, TableHeader> headerEntry : headers
|
||||
.entrySet()) {
|
||||
final Integer headerEntryKey = headerEntry.getKey();
|
||||
for (TableRow tableRow : rows) {
|
||||
headerEntry.getValue().updateWidth(
|
||||
tableRow.getValue(headerEntryKey).length());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return TableRenderer.renderTextTable(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
calculateColumnWidths();
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((headers == null) ? 0 : headers.hashCode());
|
||||
result = prime * result + ((rows == null) ? 0 : rows.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
|
||||
Table other = (Table) obj;
|
||||
this.calculateColumnWidths();
|
||||
other.calculateColumnWidths();
|
||||
if (headers == null) {
|
||||
if (other.headers != null)
|
||||
return false;
|
||||
} else if (!headers.equals(other.headers))
|
||||
return false;
|
||||
if (rows == null) {
|
||||
if (other.rows != null)
|
||||
return false;
|
||||
} else if (!rows.equals(other.rows))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright 2009-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.shell.support.table;
|
||||
|
||||
/**
|
||||
* Defines table column headers used by {@link Table}.
|
||||
*
|
||||
* @see TableRenderer
|
||||
*
|
||||
* @author Gunnar Hillert
|
||||
*
|
||||
*/
|
||||
public class TableHeader {
|
||||
|
||||
private int maxWidth = -1;
|
||||
|
||||
private int width = 0;
|
||||
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* Constructor that initializes the table header with the provided header
|
||||
* name and the with of the table header.
|
||||
*
|
||||
* @param name
|
||||
* @param width
|
||||
*/
|
||||
public TableHeader(String name, int width) {
|
||||
|
||||
super();
|
||||
this.width = width;
|
||||
this.name = name;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that initializes the table header with the provided header
|
||||
* name. The with of the table header is calculated and assigned based on
|
||||
* the provided header name.
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public TableHeader(String name) {
|
||||
super();
|
||||
this.name = name;
|
||||
|
||||
if (name == null) {
|
||||
this.width = 0;
|
||||
} else {
|
||||
this.width = name.length();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public void setWidth(int width) {
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updated the width for this particular column, but only if the value of
|
||||
* the passed-in width is higher than the value of the pre-existing width.
|
||||
*
|
||||
* @param width
|
||||
*/
|
||||
public void updateWidth(int width) {
|
||||
if (this.width < width) {
|
||||
if (this.maxWidth > 0 && this.maxWidth < width) {
|
||||
this.width = this.maxWidth;
|
||||
} else {
|
||||
this.width = width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public int getMaxWidth() {
|
||||
return maxWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defaults to -1 indicating to ignore the property.
|
||||
*
|
||||
* @param maxWidth
|
||||
* If negative or zero this property will be ignored.
|
||||
*/
|
||||
public void setMaxWidth(int maxWidth) {
|
||||
this.maxWidth = maxWidth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + maxWidth;
|
||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||
result = prime * result + width;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
TableHeader other = (TableHeader) obj;
|
||||
if (maxWidth != other.maxWidth)
|
||||
return false;
|
||||
if (name == null) {
|
||||
if (other.name != null)
|
||||
return false;
|
||||
} else if (!name.equals(other.name))
|
||||
return false;
|
||||
if (width != other.width)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* Copyright 2009-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.shell.support.table;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.springframework.shell.support.util.StringUtils;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
|
||||
/**
|
||||
* Contains utility methods for rendering data to a formatted console output.
|
||||
* E.g. it provides helper methods for rendering ASCII-based data tables.
|
||||
*
|
||||
* @author Gunnar Hillert
|
||||
* @author Thomas Risberg
|
||||
*
|
||||
*/
|
||||
public final class TableRenderer {
|
||||
|
||||
public static final String HORIZONTAL_LINE = "-------------------------------------------------------------------------------\n";
|
||||
|
||||
public static final int COLUMN_1 = 1;
|
||||
|
||||
public static final int COLUMN_2 = 2;
|
||||
|
||||
public static final int COLUMN_3 = 3;
|
||||
|
||||
public static final int COLUMN_4 = 4;
|
||||
|
||||
public static final int COLUMN_5 = 5;
|
||||
|
||||
public static final int COLUMN_6 = 6;
|
||||
|
||||
/**
|
||||
* Prevent instantiation.
|
||||
*
|
||||
*/
|
||||
private TableRenderer() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a textual representation of the list of provided Map data
|
||||
*
|
||||
* @param columns
|
||||
* List of Maps
|
||||
* @return The rendered table representation as String
|
||||
*
|
||||
*/
|
||||
public static String renderMapDataAsTable(List<Map<String, Object>> data,
|
||||
List<String> columns) {
|
||||
|
||||
Table table = new Table();
|
||||
|
||||
int col = 0;
|
||||
for (String colName : columns) {
|
||||
col++;
|
||||
table.getHeaders().put(col, new TableHeader(colName));
|
||||
if (col >= 6) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (Map<String, Object> dataRow : data) {
|
||||
|
||||
TableRow tableRow = new TableRow();
|
||||
|
||||
for (int i = 0; i < col; i++) {
|
||||
String value = dataRow.get(columns.get(i)).toString();
|
||||
table.getHeaders().get(i + 1).updateWidth(value.length());
|
||||
tableRow.addValue(i + 1, value);
|
||||
}
|
||||
|
||||
table.getRows().add(tableRow);
|
||||
}
|
||||
|
||||
return renderTextTable(table);
|
||||
}
|
||||
|
||||
public static String renderParameterInfoDataAsTable(
|
||||
Map<String, String> parameters, boolean withHeader,
|
||||
int lastColumnMaxWidth) {
|
||||
final Table table = new Table();
|
||||
|
||||
table.getHeaders().put(COLUMN_1, new TableHeader("Parameter"));
|
||||
|
||||
final TableHeader tableHeader2 = new TableHeader(
|
||||
"Value (Configured or Default)");
|
||||
tableHeader2.setMaxWidth(lastColumnMaxWidth);
|
||||
table.getHeaders().put(COLUMN_2, tableHeader2);
|
||||
|
||||
for (Entry<String, String> entry : parameters.entrySet()) {
|
||||
|
||||
final TableRow tableRow = new TableRow();
|
||||
|
||||
table.getHeaders().get(COLUMN_1)
|
||||
.updateWidth(entry.getKey().length());
|
||||
tableRow.addValue(COLUMN_1, entry.getKey());
|
||||
|
||||
int width = entry.getValue() != null ? entry.getValue().length()
|
||||
: 0;
|
||||
|
||||
table.getHeaders().get(COLUMN_2).updateWidth(width);
|
||||
tableRow.addValue(COLUMN_2, entry.getValue());
|
||||
|
||||
table.getRows().add(tableRow);
|
||||
}
|
||||
|
||||
return renderTextTable(table, withHeader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a textual representation of provided parameter map.
|
||||
*
|
||||
* @param parameters
|
||||
* Map of parameters (key, value)
|
||||
* @return The rendered table representation as String
|
||||
*
|
||||
*/
|
||||
public static String renderParameterInfoDataAsTable(
|
||||
Map<String, String> parameters) {
|
||||
return renderParameterInfoDataAsTable(parameters, true, -1);
|
||||
}
|
||||
|
||||
public static String renderTextTable(Table table) {
|
||||
return renderTextTable(table, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a textual representation of the provided {@link Table}
|
||||
*
|
||||
* @param table
|
||||
* Table data {@link Table}
|
||||
* @return The rendered table representation as String
|
||||
*/
|
||||
public static String renderTextTable(Table table, boolean withHeader) {
|
||||
|
||||
table.calculateColumnWidths();
|
||||
|
||||
final String padding = " ";
|
||||
final String headerBorder = getHeaderBorder(table.getHeaders());
|
||||
final StringBuilder textTable = new StringBuilder();
|
||||
|
||||
if (withHeader) {
|
||||
final StringBuilder headerline = new StringBuilder();
|
||||
for (TableHeader header : table.getHeaders().values()) {
|
||||
|
||||
if (header.getName().length() > header.getWidth()) {
|
||||
Iterable<String> chunks = Splitter.fixedLength(
|
||||
header.getWidth()).split(header.getName());
|
||||
int length = headerline.length();
|
||||
boolean first = true;
|
||||
for (String chunk : chunks) {
|
||||
final String lineToAppend;
|
||||
if (first) {
|
||||
lineToAppend = padding
|
||||
+ StringUtils.padRight(chunk,
|
||||
header.getWidth());
|
||||
} else {
|
||||
lineToAppend = StringUtils.padLeft("", length)
|
||||
+ padding
|
||||
+ StringUtils.padRight(chunk,
|
||||
header.getWidth());
|
||||
}
|
||||
first = false;
|
||||
headerline.append(lineToAppend);
|
||||
headerline.append("\n");
|
||||
}
|
||||
headerline.deleteCharAt(headerline.lastIndexOf("\n"));
|
||||
} else {
|
||||
String lineToAppend = padding
|
||||
+ StringUtils.padRight(header.getName(),
|
||||
header.getWidth());
|
||||
headerline.append(lineToAppend);
|
||||
}
|
||||
}
|
||||
textTable.append(org.springframework.util.StringUtils
|
||||
.trimTrailingWhitespace(headerline.toString()));
|
||||
textTable.append("\n");
|
||||
}
|
||||
|
||||
textTable.append(headerBorder);
|
||||
|
||||
for (TableRow row : table.getRows()) {
|
||||
StringBuilder rowLine = new StringBuilder();
|
||||
for (Entry<Integer, TableHeader> entry : table.getHeaders()
|
||||
.entrySet()) {
|
||||
String value = row.getValue(entry.getKey());
|
||||
if (value.length() > entry.getValue().getWidth()) {
|
||||
Iterable<String> chunks = Splitter.fixedLength(
|
||||
entry.getValue().getWidth()).split(value);
|
||||
int length = rowLine.length();
|
||||
boolean first = true;
|
||||
for (String chunk : chunks) {
|
||||
final String lineToAppend;
|
||||
if (first) {
|
||||
lineToAppend = padding
|
||||
+ StringUtils.padRight(chunk, entry
|
||||
.getValue().getWidth());
|
||||
} else {
|
||||
lineToAppend = StringUtils.padLeft("", length)
|
||||
+ padding
|
||||
+ StringUtils.padRight(chunk, entry
|
||||
.getValue().getWidth());
|
||||
}
|
||||
first = false;
|
||||
rowLine.append(lineToAppend);
|
||||
rowLine.append("\n");
|
||||
}
|
||||
rowLine.deleteCharAt(rowLine.lastIndexOf("\n"));
|
||||
} else {
|
||||
String lineToAppend = padding
|
||||
+ StringUtils.padRight(value, entry.getValue()
|
||||
.getWidth());
|
||||
rowLine.append(lineToAppend);
|
||||
}
|
||||
}
|
||||
textTable.append(org.springframework.util.StringUtils
|
||||
.trimTrailingWhitespace(rowLine.toString()));
|
||||
textTable.append("\n");
|
||||
}
|
||||
|
||||
if (!withHeader) {
|
||||
textTable.append(headerBorder);
|
||||
}
|
||||
|
||||
return textTable.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the Table header border, based on the map of provided headers.
|
||||
*
|
||||
* @param headers
|
||||
* Map of headers containing meta information e.g. name+width of
|
||||
* header
|
||||
* @return Returns the rendered header border as String
|
||||
*/
|
||||
public static String getHeaderBorder(Map<Integer, TableHeader> headers) {
|
||||
|
||||
final StringBuilder headerBorder = new StringBuilder();
|
||||
|
||||
for (TableHeader header : headers.values()) {
|
||||
headerBorder.append(StringUtils.padRight(" ",
|
||||
header.getWidth() + 2, '-'));
|
||||
}
|
||||
headerBorder.append("\n");
|
||||
|
||||
return headerBorder.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2009-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.shell.support.table;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Holds the table rows used by {@link Table}.
|
||||
*
|
||||
* @see TableRenderer
|
||||
*
|
||||
* @author Gunnar Hillert
|
||||
* @author Ilayaperumal Gopinathan
|
||||
*
|
||||
*/
|
||||
public class TableRow {
|
||||
|
||||
/** Holds the data for the column */
|
||||
private Map<Integer, String> data = new HashMap<Integer, String>();
|
||||
|
||||
public void setData(Map<Integer, String> data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a value from this row.
|
||||
*
|
||||
* @param key
|
||||
* Column for which to return the value for
|
||||
* @return Value of the specified column within this row
|
||||
*
|
||||
*/
|
||||
public String getValue(Integer key) {
|
||||
return data.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a value to the to the specified column within this row.
|
||||
*
|
||||
* @param column
|
||||
* @param value
|
||||
*/
|
||||
public TableRow addValue(Integer column, String value) {
|
||||
this.data.put(column, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((data == null) ? 0 : data.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
TableRow other = (TableRow) obj;
|
||||
if (data == null) {
|
||||
if (other.data != null)
|
||||
return false;
|
||||
} else if (!data.equals(other.data))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,279 @@
|
||||
/*
|
||||
* Copyright 2009-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.shell.support.util;
|
||||
|
||||
|
||||
/**
|
||||
* Utility methods for Strings focused on the use in formatting of tables. padLeft methods taken from
|
||||
* Commons Lang 2.6 to avoid an extra compile time dependency.
|
||||
*
|
||||
* @author Gunnar Hillert
|
||||
* @author Mark Pollack
|
||||
*
|
||||
*/
|
||||
public class StringUtils {
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The maximum size to which the padding constant(s) can expand.
|
||||
* </p>
|
||||
*/
|
||||
private static final int PAD_LIMIT = 8192;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Left pad a String with spaces (' ').
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The String is padded to the size of <code>size</code>.
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* StringUtils.leftPad(null, *) = null
|
||||
* StringUtils.leftPad("", 3) = " "
|
||||
* StringUtils.leftPad("bat", 3) = "bat"
|
||||
* StringUtils.leftPad("bat", 5) = " bat"
|
||||
* StringUtils.leftPad("bat", 1) = "bat"
|
||||
* StringUtils.leftPad("bat", -1) = "bat"
|
||||
* </pre>
|
||||
*
|
||||
* @param str
|
||||
* the String to pad out, may be null
|
||||
* @param size
|
||||
* the size to pad to
|
||||
* @return left padded String or original String if no padding is necessary,
|
||||
* <code>null</code> if null String input
|
||||
*/
|
||||
public static String padLeft(String str, int size) {
|
||||
return padLeft(str, size, ' ');
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Left pad a String with a specified character.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Pad to a size of <code>size</code>.
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* StringUtils.leftPad(null, *, *) = null
|
||||
* StringUtils.leftPad("", 3, 'z') = "zzz"
|
||||
* StringUtils.leftPad("bat", 3, 'z') = "bat"
|
||||
* StringUtils.leftPad("bat", 5, 'z') = "zzbat"
|
||||
* StringUtils.leftPad("bat", 1, 'z') = "bat"
|
||||
* StringUtils.leftPad("bat", -1, 'z') = "bat"
|
||||
* </pre>
|
||||
*
|
||||
* @param str
|
||||
* the String to pad out, may be null
|
||||
* @param size
|
||||
* the size to pad to
|
||||
* @param padChar
|
||||
* the character to pad with
|
||||
* @return left padded String or original String if no padding is necessary,
|
||||
* <code>null</code> if null String input
|
||||
* @since 2.0
|
||||
*/
|
||||
public static String padLeft(String str, int size, char padChar) {
|
||||
if (str == null) {
|
||||
return null;
|
||||
}
|
||||
int pads = size - str.length();
|
||||
if (pads <= 0) {
|
||||
return str; // returns original String when possible
|
||||
}
|
||||
if (pads > PAD_LIMIT) {
|
||||
return padLeft(str, size, String.valueOf(padChar));
|
||||
}
|
||||
return padding(pads, padChar).concat(str);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Left pad a String with a specified String.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Pad to a size of <code>size</code>.
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* StringUtils.leftPad(null, *, *) = null
|
||||
* StringUtils.leftPad("", 3, "z") = "zzz"
|
||||
* StringUtils.leftPad("bat", 3, "yz") = "bat"
|
||||
* StringUtils.leftPad("bat", 5, "yz") = "yzbat"
|
||||
* StringUtils.leftPad("bat", 8, "yz") = "yzyzybat"
|
||||
* StringUtils.leftPad("bat", 1, "yz") = "bat"
|
||||
* StringUtils.leftPad("bat", -1, "yz") = "bat"
|
||||
* StringUtils.leftPad("bat", 5, null) = " bat"
|
||||
* StringUtils.leftPad("bat", 5, "") = " bat"
|
||||
* </pre>
|
||||
*
|
||||
* @param str
|
||||
* the String to pad out, may be null
|
||||
* @param size
|
||||
* the size to pad to
|
||||
* @param padStr
|
||||
* the String to pad with, null or empty treated as single space
|
||||
* @return left padded String or original String if no padding is necessary,
|
||||
* <code>null</code> if null String input
|
||||
*/
|
||||
public static String padLeft(String str, int size, String padStr) {
|
||||
if (str == null) {
|
||||
return null;
|
||||
}
|
||||
if (isEmpty(padStr)) {
|
||||
padStr = " ";
|
||||
}
|
||||
int padLen = padStr.length();
|
||||
int strLen = str.length();
|
||||
int pads = size - strLen;
|
||||
if (pads <= 0) {
|
||||
return str; // returns original String when possible
|
||||
}
|
||||
if (padLen == 1 && pads <= PAD_LIMIT) {
|
||||
return padLeft(str, size, padStr.charAt(0));
|
||||
}
|
||||
|
||||
if (pads == padLen) {
|
||||
return padStr.concat(str);
|
||||
} else if (pads < padLen) {
|
||||
return padStr.substring(0, pads).concat(str);
|
||||
} else {
|
||||
char[] padding = new char[pads];
|
||||
char[] padChars = padStr.toCharArray();
|
||||
for (int i = 0; i < pads; i++) {
|
||||
padding[i] = padChars[i % padLen];
|
||||
}
|
||||
return new String(padding).concat(str);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Checks if a String is empty ("") or null.
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* StringUtils.isEmpty(null) = true
|
||||
* StringUtils.isEmpty("") = true
|
||||
* StringUtils.isEmpty(" ") = false
|
||||
* StringUtils.isEmpty("bob") = false
|
||||
* StringUtils.isEmpty(" bob ") = false
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* NOTE: This method changed in Lang version 2.0. It no longer trims the
|
||||
* String. That functionality is available in isBlank().
|
||||
* </p>
|
||||
*
|
||||
* @param str
|
||||
* the String to check, may be null
|
||||
* @return <code>true</code> if the String is empty or null
|
||||
*/
|
||||
public static boolean isEmpty(String str) {
|
||||
return str == null || str.length() == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Returns padding using the specified delimiter repeated to a given length.
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* StringUtils.padding(0, 'e') = ""
|
||||
* StringUtils.padding(3, 'e') = "eee"
|
||||
* StringUtils.padding(-2, 'e') = IndexOutOfBoundsException
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Note: this method doesn't not support padding with <a
|
||||
* href="http://www.unicode.org/glossary/#supplementary_character">Unicode
|
||||
* Supplementary Characters</a> as they require a pair of <code>char</code>s
|
||||
* to be represented. If you are needing to support full I18N of your
|
||||
* applications consider using {@link #repeat(String, int)} instead.
|
||||
* </p>
|
||||
*
|
||||
* @param repeat
|
||||
* number of times to repeat delim
|
||||
* @param padChar
|
||||
* character to repeat
|
||||
* @return String with repeated character
|
||||
* @throws IndexOutOfBoundsException
|
||||
* if <code>repeat < 0</code>
|
||||
* @see #repeat(String, int)
|
||||
*/
|
||||
private static String padding(int repeat, char padChar)
|
||||
throws IndexOutOfBoundsException {
|
||||
if (repeat < 0) {
|
||||
throw new IndexOutOfBoundsException(
|
||||
"Cannot pad a negative amount: " + repeat);
|
||||
}
|
||||
final char[] buf = new char[repeat];
|
||||
for (int i = 0; i < buf.length; i++) {
|
||||
buf[i] = padChar;
|
||||
}
|
||||
return new String(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Right-pad a String with a configurable padding character.
|
||||
*
|
||||
* @param inputString
|
||||
* The String to pad. A {@code null} String will be treated like
|
||||
* an empty String.
|
||||
* @param size
|
||||
* Pad String by the number of characters.
|
||||
* @param paddingChar
|
||||
* The character to pad the String with.
|
||||
* @return The padded String. If the provided String is null, an empty
|
||||
* String is returned.
|
||||
*/
|
||||
public static String padRight(String inputString, int size, char paddingChar) {
|
||||
|
||||
final String stringToPad;
|
||||
|
||||
if (inputString == null) {
|
||||
stringToPad = "";
|
||||
} else {
|
||||
stringToPad = inputString;
|
||||
}
|
||||
|
||||
StringBuilder padded = new StringBuilder(stringToPad);
|
||||
while (padded.length() < size) {
|
||||
padded.append(paddingChar);
|
||||
}
|
||||
return padded.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Right-pad the provided String with empty spaces.
|
||||
*
|
||||
* @param string
|
||||
* The String to pad
|
||||
* @param size
|
||||
* Pad String by the number of characters.
|
||||
* @return The padded String. If the provided String is null, an empty
|
||||
* String is returned.
|
||||
*/
|
||||
public static String padRight(String string, int size) {
|
||||
return padRight(string, size, ' ');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright 2009-2013 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.shell.support.table;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
/**
|
||||
* @author Gunnar Hillert
|
||||
*
|
||||
*/
|
||||
public class TableRendererTest {
|
||||
|
||||
@Test
|
||||
public void testRenderTextTable() {
|
||||
|
||||
final Table table = new Table();
|
||||
table.addHeader(1, new TableHeader("Tap Name"))
|
||||
.addHeader(2, new TableHeader("Stream Name"))
|
||||
.addHeader(3, new TableHeader("Tap Definition"));
|
||||
|
||||
for (int i = 1; i <= 3; i++) {
|
||||
final TableRow row = new TableRow();
|
||||
row.addValue(1, "tap" + i)
|
||||
.addValue(2, "ticktock")
|
||||
.addValue(3, "tap@ticktock|log");
|
||||
table.getRows().add(row);
|
||||
}
|
||||
|
||||
String expectedTableAsString = null;
|
||||
|
||||
final InputStream inputStream = getClass()
|
||||
.getClassLoader()
|
||||
.getResourceAsStream("testRenderTextTable-expected-output.txt");
|
||||
|
||||
assertNotNull("The inputstream is null.", inputStream);
|
||||
|
||||
try {
|
||||
expectedTableAsString = FileCopyUtils.copyToString(new InputStreamReader(inputStream));
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
}
|
||||
|
||||
final String tableRenderedAsString = TableRenderer.renderTextTable(table);
|
||||
|
||||
assertEquals(expectedTableAsString.replaceAll("\r", ""), tableRenderedAsString);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRenderTextTableWithSingleColumn() {
|
||||
|
||||
final Table table = new Table();
|
||||
table.addHeader(1, new TableHeader("Gauge name"));
|
||||
|
||||
final TableRow row = new TableRow();
|
||||
row.addValue(1, "simplegauge");
|
||||
table.getRows().add(row);
|
||||
|
||||
String expectedTableAsString = null;
|
||||
|
||||
final InputStream inputStream = getClass()
|
||||
.getClassLoader()
|
||||
.getResourceAsStream("testRenderTextTable-single-column-expected-output.txt");
|
||||
|
||||
assertNotNull("The inputstream is null.", inputStream);
|
||||
|
||||
try {
|
||||
expectedTableAsString = FileCopyUtils.copyToString(new InputStreamReader(inputStream));
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
}
|
||||
|
||||
final String tableRenderedAsString = TableRenderer.renderTextTable(table);
|
||||
assertEquals(expectedTableAsString.replaceAll("\r", ""), tableRenderedAsString);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRenderTextTableWithSingleColumnAndWidthOf4() {
|
||||
|
||||
final Table table = new Table();
|
||||
final TableHeader tableHeader = new TableHeader("Gauge name");
|
||||
tableHeader.setMaxWidth(4);
|
||||
table.addHeader(1, tableHeader);
|
||||
|
||||
final TableRow row = new TableRow();
|
||||
row.addValue(1, "simplegauge");
|
||||
table.getRows().add(row);
|
||||
|
||||
String expectedTableAsString = null;
|
||||
|
||||
final InputStream inputStream = getClass()
|
||||
.getClassLoader()
|
||||
.getResourceAsStream("testRenderTextTable-single-column-width4-expected-output.txt");
|
||||
|
||||
assertNotNull("The inputstream is null.", inputStream);
|
||||
|
||||
try {
|
||||
expectedTableAsString = FileCopyUtils.copyToString(new InputStreamReader(inputStream));
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
}
|
||||
|
||||
final String tableRenderedAsString = TableRenderer.renderTextTable(table);
|
||||
assertEquals(expectedTableAsString.replaceAll("\r", ""), tableRenderedAsString);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRenderParameterInfoDataAsTableWithMaxWidth() {
|
||||
|
||||
final Map<String, String> values = new TreeMap<String, String>();
|
||||
|
||||
values.put("Key1", "Lorem ipsum dolor sit posuere.");
|
||||
values.put("My super key 2", "Lorem ipsum");
|
||||
|
||||
String expectedTableAsString = null;
|
||||
|
||||
final InputStream inputStream = getClass()
|
||||
.getClassLoader()
|
||||
.getResourceAsStream("testRenderParameterInfoDataAsTableWithMaxWidth.txt");
|
||||
|
||||
assertNotNull("The inputstream is null.", inputStream);
|
||||
|
||||
try {
|
||||
expectedTableAsString = FileCopyUtils.copyToString(new InputStreamReader(inputStream));
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
}
|
||||
|
||||
final String tableRenderedAsString = TableRenderer.renderParameterInfoDataAsTable(values, false, 20);
|
||||
assertEquals(expectedTableAsString.replaceAll("\r", ""), tableRenderedAsString);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRenderTableWithRowShorthand() {
|
||||
|
||||
final Table table = new Table();
|
||||
table.addHeader(1, new TableHeader("Property"))
|
||||
.addHeader(2, new TableHeader("Value"));
|
||||
|
||||
table.addRow("Job Execution ID", String.valueOf(1))
|
||||
.addRow("Job Name", "My Job Name")
|
||||
.addRow("Start Time", "12:30")
|
||||
.addRow("Step Execution Count", String.valueOf(12))
|
||||
.addRow("Status", "COMPLETED");
|
||||
|
||||
assertNotNull(table.toString());
|
||||
|
||||
final InputStream inputStream = getClass()
|
||||
.getClassLoader()
|
||||
.getResourceAsStream("testRenderTableWithRowShorthand-expected-output.txt");
|
||||
|
||||
assertNotNull("The inputstream is null.", inputStream);
|
||||
|
||||
String expectedTableAsString = null;
|
||||
|
||||
try {
|
||||
expectedTableAsString = FileCopyUtils.copyToString(new InputStreamReader(inputStream));
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
}
|
||||
assertEquals(expectedTableAsString.replaceAll("\r", ""), table.toString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2011-2012 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.shell.support.util;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class StringUtilsTest {
|
||||
|
||||
@Test
|
||||
public void testPadRightWithNullString() {
|
||||
assertEquals(" ", StringUtils.padRight(null, 5));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPadRightWithEmptyString() {
|
||||
assertEquals(" ", StringUtils.padRight("", 5));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPadRight() {
|
||||
assertEquals("foo ", StringUtils.padRight("foo", 5));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLeftPad_StringInt() {
|
||||
assertEquals(null, StringUtils.padLeft(null, 5));
|
||||
assertEquals(" ", StringUtils.padLeft("", 5));
|
||||
assertEquals(" abc", StringUtils.padLeft("abc", 5));
|
||||
assertEquals("abc", StringUtils.padLeft("abc", 2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLeftPad_StringIntChar() {
|
||||
assertEquals(null, StringUtils.padLeft(null, 5, ' '));
|
||||
assertEquals(" ", StringUtils.padLeft("", 5, ' '));
|
||||
assertEquals(" abc", StringUtils.padLeft("abc", 5, ' '));
|
||||
assertEquals("xxabc", StringUtils.padLeft("abc", 5, 'x'));
|
||||
assertEquals("\uffff\uffffabc", StringUtils.padLeft("abc", 5, '\uffff'));
|
||||
assertEquals("abc", StringUtils.padLeft("abc", 2, ' '));
|
||||
String str = StringUtils.padLeft("aaa", 10000, 'a'); // bigger than pad length
|
||||
assertEquals(10000, str.length());
|
||||
//Note, did not include the next assert to avoid pulling in a long chain of methods from commons lang
|
||||
//assertEquals(true, StringUtils.containsOnly(str, new char[] {'a'}));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLeftPad_StringIntString() {
|
||||
assertEquals(null, StringUtils.padLeft(null, 5, "-+"));
|
||||
assertEquals(null, StringUtils.padLeft(null, 5, null));
|
||||
assertEquals(" ", StringUtils.padLeft("", 5, " "));
|
||||
assertEquals("-+-+abc", StringUtils.padLeft("abc", 7, "-+"));
|
||||
assertEquals("-+~abc", StringUtils.padLeft("abc", 6, "-+~"));
|
||||
assertEquals("-+abc", StringUtils.padLeft("abc", 5, "-+~"));
|
||||
assertEquals("abc", StringUtils.padLeft("abc", 2, " "));
|
||||
assertEquals("abc", StringUtils.padLeft("abc", -1, " "));
|
||||
assertEquals(" abc", StringUtils.padLeft("abc", 5, null));
|
||||
assertEquals(" abc", StringUtils.padLeft("abc", 5, ""));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
-------------- --------------------
|
||||
Key1 Lorem ipsum dolor si
|
||||
t posuere.
|
||||
My super key 2 Lorem ipsum
|
||||
-------------- --------------------
|
||||
@@ -0,0 +1,7 @@
|
||||
Property Value
|
||||
-------------------- -----------
|
||||
Job Execution ID 1
|
||||
Job Name My Job Name
|
||||
Start Time 12:30
|
||||
Step Execution Count 12
|
||||
Status COMPLETED
|
||||
@@ -0,0 +1,5 @@
|
||||
Tap Name Stream Name Tap Definition
|
||||
-------- ----------- ----------------
|
||||
tap1 ticktock tap@ticktock|log
|
||||
tap2 ticktock tap@ticktock|log
|
||||
tap3 ticktock tap@ticktock|log
|
||||
@@ -0,0 +1,3 @@
|
||||
Gauge name
|
||||
-----------
|
||||
simplegauge
|
||||
@@ -0,0 +1,7 @@
|
||||
Gaug
|
||||
e na
|
||||
me
|
||||
----
|
||||
simp
|
||||
lega
|
||||
uge
|
||||
Reference in New Issue
Block a user