blob: 06839fccdbf80869bbc27d8db681cbf06a2fee03 [file] [log] [blame]
/*
* 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.unomi.common;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
/**
* An in memory table structure for storing data and performing operations such as sorting it, or generating JSON or
* CSV outputs.
*/
public class DataTable {
List<Row> rows = new ArrayList<>();
int maxColumns = 0;
public static final EmptyCell EMPTY_CELL = new EmptyCell();
public DataTable() {
}
public List<Row> getRows() {
return rows;
}
public void addRow(Comparable... rowData) {
if (rowData == null) {
return;
}
if (rowData.length > maxColumns) {
maxColumns = rowData.length;
}
Row row = new Row();
for (Comparable dataObject : rowData) {
row.addData(dataObject);
}
rows.add(row);
}
public int getMaxColumns() {
return maxColumns;
}
public static enum SortOrder {
ASCENDING,
DESCENDING;
}
public static class SortCriteria {
Integer columnIndex;
SortOrder sortOrder;
public SortCriteria(Integer columnIndex, SortOrder sortOrder) {
this.columnIndex = columnIndex;
this.sortOrder = sortOrder;
}
}
public class Row {
List<Comparable> rowData = new ArrayList<>();
public void addData(Comparable data) {
rowData.add(data);
}
public Comparable getData(int index) {
if (index >= maxColumns) {
throw new ArrayIndexOutOfBoundsException("Index on row data (" + index + ") is larger than max columns (" + maxColumns + ")");
}
if (index >= rowData.size()) {
return EMPTY_CELL;
}
return rowData.get(index);
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("[");
sb.append(rowData);
sb.append(']');
return sb.toString();
}
}
public void sort(SortCriteria... sortCriterias) {
rows.sort(new Comparator<Row>() {
@Override
public int compare(Row row1, Row row2) {
int i = 0;
while (i < sortCriterias.length) {
Comparable row1Data = row1.getData(sortCriterias[i].columnIndex);
Comparable row2Data = row2.getData(sortCriterias[i].columnIndex);
if (row1Data == EMPTY_CELL && row2Data != EMPTY_CELL) {
if (sortCriterias[i].sortOrder == SortOrder.ASCENDING) {
return -1;
} else {
return 1;
}
}
if (row2Data == EMPTY_CELL && row1Data != EMPTY_CELL) {
if (sortCriterias[i].sortOrder == SortOrder.ASCENDING) {
return 1;
} else {
return -1;
}
}
int rowComparison = row1Data.compareTo(row2Data);
if (rowComparison == 0) {
// rows are equal on this criteria, let's go to the next criteria if it exists
if (i < sortCriterias.length) {
i++;
} else {
return 0;
}
} else {
if (sortCriterias[i].sortOrder == SortOrder.ASCENDING) {
return rowComparison;
} else {
return -rowComparison;
}
}
}
return 0;
}
});
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("[");
sb.append(rows);
sb.append(']');
return sb.toString();
}
public static class EmptyCell implements Comparable {
@Override
public int compareTo(Object o) {
if (o instanceof EmptyCell) {
return 0;
}
return -1;
}
@Override
public String toString() {
return "";
}
}
public String toCSV(String... headers) {
StringBuilder stringBuilder = new StringBuilder();
CSVFormat csvFormat = CSVFormat.DEFAULT;
if (headers != null && headers.length > 0) {
csvFormat = CSVFormat.DEFAULT.withHeader(headers);
}
try {
CSVPrinter printer = csvFormat.print(stringBuilder);
for (Row row : rows) {
List<String> values = new ArrayList<>();
for (int i = 0; i < maxColumns; i++) {
values.add(row.getData(i).toString());
}
printer.printRecord(values.toArray(new String[values.size()]));
}
printer.close();
} catch (IOException e) {
e.printStackTrace(); // this will probably never happen as we are writing to a String.
}
return stringBuilder.toString();
}
}