All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.carrot2.text.util.TabularOutput Maven / Gradle / Ivy
Go to download
Carrot2 search results clustering framework. Minimal functional subset
(core algorithms and infrastructure, no document sources).
/*
* Carrot2 project.
*
* Copyright (C) 2002-2013, Dawid Weiss, Stanisław Osiński.
* All rights reserved.
*
* Refer to the full license file "carrot2.LICENSE"
* in the root folder of the repository checkout or at:
* http://www.carrot2.org/carrot2.LICENSE
*/
package org.carrot2.text.util;
import java.io.*;
import java.util.*;
import java.util.Map.Entry;
import org.apache.commons.lang.StringUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
/**
* Tabular output data dump with automatically adjusted column widths and some other
* utilities.
*/
public final class TabularOutput
{
/** Column separator. */
private String columnSeparator = " ";
/** Declared columns (in order). */
final List columns = Lists.newArrayList();
/** */
final HashMap columnsByName = Maps.newHashMap();
/** Currently buffered row. */
final List currentRow = Lists.newArrayList();
/** Currently buffered rows. */
final List> data = Lists.newArrayList();
/**
* A writer to write the output to.
*/
private Writer writer;
/**
* Flush every n-lines.
* @see #flush()
*/
private int flushCount = 1;
/**
* Row count since the last flush.
*/
private int rowCount;
/**
* Any committed and emitted output?
*/
private boolean outputEmitted;
/**
* Row listeners.
*/
private ArrayList listeners = new ArrayList();
/**
* Where to write the output to.
*/
public TabularOutput(Writer writer)
{
this.writer = writer;
}
/**
* An output to {@link System#out}.
*/
public TabularOutput()
{
this(new PrintWriter(System.out));
}
/**
* A listener notified when a row is complete and being emitted.
*/
public static interface RowListener
{
public void newRow(List columns, List values);
}
/**
* Column alignment.
*/
public static enum Alignment
{
LEFT, RIGHT, CENTER;
public String align(String string, int size)
{
switch (this)
{
case LEFT:
return StringUtils.rightPad(string, size);
case RIGHT:
return StringUtils.leftPad(string, size);
default:
return StringUtils.center(string, size);
}
}
}
/**
* Column specification.
*/
public final class ColumnSpec
{
/** Column name. */
public final String name;
/** Alignment. */
private Alignment alignment;
/** Formatter for the value. */
String format;
/** Max width of this column observed so far. */
int maxWidth;
/** Positional index of this column. */
public final int index;
public ColumnSpec(String name, int index)
{
this.name = name;
this.index = index;
}
public TabularOutput tabularOutput()
{
return TabularOutput.this;
}
/**
* Sets column flush on the last added column.
*/
public ColumnSpec alignLeft()
{
checkNoDataAdded();
this.alignment = Alignment.LEFT;
return this;
}
/**
* Sets column flush on the last added column.
*/
public ColumnSpec alignRight()
{
checkNoDataAdded();
this.alignment = Alignment.RIGHT;
return this;
}
/**
* Sets column flush on the last added column.
*/
public ColumnSpec alignCenter()
{
checkNoDataAdded();
this.alignment = Alignment.CENTER;
return this;
}
public String toString()
{
return name;
}
public ColumnSpec format(String formatString)
{
if (format != null) {
throw new IllegalStateException("Format already initialized to: " + format);
}
if (formatString == null) {
formatString = "%s";
}
format = formatString;
return this;
}
boolean updateWidth(int newLength)
{
if (newLength > maxWidth) {
maxWidth = newLength;
return true;
}
return false;
}
private String formatValue(Object object)
{
String formatted;
if (object == null) {
formatted = "--";
} else {
object = toStringAdapters(object);
if (format == null) {
format(defaultSpec(object.getClass()).format);
}
if (alignment == null) {
alignment = defaultSpec(object.getClass()).alignment;
}
formatted = String.format(format, object);
}
return formatted;
}
public String align(String text)
{
Alignment alignment = this.alignment;
if (alignment == null) {
alignment = Alignment.RIGHT;
}
return alignment.align(text, maxWidth);
}
}
/**
* Apply toString adapters to an object, if any.
*/
private Object toStringAdapters(Object object)
{
if (object instanceof char[]) return new String((char[]) object);
if (object instanceof byte[]) return Arrays.toString((byte[]) object);
if (object instanceof short[]) return Arrays.toString((short[]) object);
if (object instanceof int[]) return Arrays.toString((int[]) object);
if (object instanceof long[]) return Arrays.toString((long[]) object);
if (object instanceof float[]) return Arrays.toString((float[]) object);
if (object instanceof double[]) return Arrays.toString((double[]) object);
return object;
}
/**
* Adds a listener to receive information about each row.
*/
public TabularOutput addListener(RowListener listener)
{
this.listeners.add(listener);
return this;
}
/**
* Provide a default column spec for a given object class.
*/
private final LinkedHashMap, ColumnSpec> defaultFormats =
new LinkedHashMap, ColumnSpec>();
{
defaultFormats.put(Object.class,
defaultFormat(Object.class)
.format("%s"));
}
/**
* Return default format for a given class.
*/
ColumnSpec defaultSpec(Class> clazz)
{
ArrayList, ColumnSpec>> arrayList =
new ArrayList,ColumnSpec>>(defaultFormats.entrySet());
Collections.reverse(arrayList);
for (Map.Entry,ColumnSpec> e : arrayList) {
if (e.getKey().isAssignableFrom(clazz)) {
return e.getValue();
}
}
throw new IllegalStateException("No default column spec?");
}
/**
* Default column specification for a given class.
*/
public ColumnSpec defaultFormat(Class> valueClass)
{
ColumnSpec colSpec = defaultFormats.get(valueClass);
if (colSpec == null) {
colSpec = new ColumnSpec("default-" + valueClass.getSimpleName(), -1);
defaultFormats.put(valueClass, colSpec);
}
return colSpec;
}
/**
* Adds a column to the tabular's layout. Columns must be added before adding data.
*/
public ColumnSpec addColumn(String name)
{
if (!autoAddColumns) checkNoDataAdded();
ColumnSpec cs = new ColumnSpec(name, columns.size());
columns.add(cs);
if (columnsByName.put(cs.name, cs) != null) {
throw new IllegalArgumentException("Two columns with the same name: " + name);
}
columnsChanged = true;
return cs;
}
public TabularOutput columnSeparator(String separator)
{
checkNoDataAdded();
this.columnSeparator = separator;
return this;
}
public TabularOutput nextRow()
{
data.add(Lists.newArrayList(currentRow));
currentRow.clear();
if (++rowCount >= flushCount) {
rowCount = 0;
flush();
}
return this;
}
/**
* Sequentially adds column data to the current row.
*/
public TabularOutput rowData(Object... columnData)
{
if (currentRow.size() + columnData.length > columns.size())
{
throw new IllegalStateException(
"Row would be larger than the number of columns: " + columns.size()
+ ", row: " + currentRow.size() + " attempted add: " + columnData.length);
}
currentRow.addAll(Arrays.asList(columnData));
return this;
}
/**
* Add new columns automatically as they're added?
*/
private boolean autoAddColumns = true;
private boolean columnsChanged = false;
public TabularOutput rowData(String columnName, Object value)
{
ColumnSpec columnSpec = columnsByName.get(columnName);
if (columnSpec == null) {
if (autoAddColumns) {
columnSpec = addColumn(columnName);
} else {
throw new IllegalArgumentException("No such column: " + columnName);
}
}
int index = columnSpec.index;
while (index >= currentRow.size())
{
currentRow.add(null);
}
currentRow.set(index, value);
return this;
}
/**
* Flush automatically every n-lines.
* @see #flush()
*/
public TabularOutput flushEvery(int n)
{
this.flushCount = n;
return this;
}
/**
* Flush current data rows. May emit header.
*/
public TabularOutput flush()
{
try {
return flush0();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private TabularOutput flush0() throws IOException
{
if (data.size() > 0) {
// Update column widths.
boolean widthsChanged = false;
for (List row : data)
{
for (int i = 0; i < columns.size(); i++)
{
final ColumnSpec col = columns.get(i);
final String formatted = col.formatValue(i < row.size() ? row.get(i): null);
widthsChanged |= col.updateWidth(formatted.length());
if (i >= row.size()) {
row.add(null);
}
}
}
// If any changes have been detected, re-emit headers.
if (widthsChanged || columnsChanged)
{
if (outputEmitted) {
writer.write("\n");
}
outputEmitted = true;
for (int i = 0; i < columns.size(); i++)
{
ColumnSpec col = columns.get(i);
String header = col.align(col.name);
col.updateWidth(header.length());
writer.write(header);
writer.write(columnSeparator);
}
writer.write("\n");
columnsChanged = false;
}
// Finally, emit the data so far and clear it.
for (List row : data)
{
for (RowListener listener : listeners)
{
listener.newRow(columns, row);
}
for (int i = 0; i < row.size(); i++)
{
final ColumnSpec col = columns.get(i);
final String formatted = col.formatValue(i < row.size() ? row.get(i): null);
writer.write(col.align(formatted));
writer.write(columnSeparator);
}
writer.write("\n");
}
data.clear();
writer.flush();
}
return this;
}
private void checkNoDataAdded()
{
if (currentRow.size() != 0 || data.size() != 0) throw new IllegalStateException(
"Data already added.");
}
public List getColumns()
{
return Collections.unmodifiableList(columns);
}
}