/* * Copyright 2014 Red Hat, Inc. and/or its affiliates. * * 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.dashbuilder.dataset.impl; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.ArrayList; import org.dashbuilder.dataset.ColumnType; import org.dashbuilder.dataset.DataColumn; import org.dashbuilder.dataset.DataSet; import org.dashbuilder.dataset.DataSetMetadata; import org.dashbuilder.dataset.def.DataSetDef; import org.dashbuilder.dataset.group.GroupFunction; public class DataSetImpl implements DataSet { protected DataSetDef definition; protected String uuid = null; protected Date creationDate = new Date(); protected List<DataColumnImpl> columns = new ArrayList<DataColumnImpl>(); protected int rowCountNonTrimmed = -1; public DataSetMetadata getMetadata() { return new DataSetMetadataImpl(this); } public DataSetDef getDefinition() { return definition; } public void setDefinition(DataSetDef definition) { this.definition = definition; } public String getUUID() { return uuid; } public void setUUID(String uuid) { this.uuid = uuid; } public Date getCreationDate() { return creationDate; } public void setCreationDate(Date creationDate) { this.creationDate = creationDate; } public List<DataColumn> getColumns() { return new ArrayList<DataColumn>(columns); } public void setColumns(List<DataColumn> columnList) { columns.clear(); for (DataColumn column : columnList) { columns.add((DataColumnImpl) column); } } public DataColumn getColumnById(String id) { for (DataColumn column : columns) { if (column.getId().equalsIgnoreCase(id)) { return column; } GroupFunction gf = column.getGroupFunction(); if (gf != null && gf.getSourceId() != null && gf.getSourceId().equalsIgnoreCase(id)) { return column; } } return null; } public DataColumn getColumnByIndex(int index) { if (columns == null || columns.isEmpty()) { throw new IllegalArgumentException("The data set is empty."); } if (index >= columns.size()) { throw new IllegalArgumentException("The column index " + index + " is out of bounds: " + (columns.size()-1)); } return columns.get(index); } @Override public int getColumnIndex( DataColumn dataColumn ) { if (dataColumn == null || "".equals(dataColumn.getId())) { throw new IllegalArgumentException("Wrong column specified."); } for (int i = 0; i < columns.size(); i++) { if ( dataColumn.getId().equalsIgnoreCase( columns.get( i ).getId() ) ) return i; } throw new IllegalArgumentException( "The column with id " + dataColumn.getId() + " does not exist." ); } public DataSet addColumn(String id, ColumnType type) { return addColumn(id, type, null); } public DataSet addColumn(String id, ColumnType type, List values) { DataColumnImpl c = new DataColumnImpl(); c.setDataSet(this); c.setId(id); c.setColumnType(type); if (values != null) c.setValues(values); columns.add(c); return this; } public DataSet addColumn(DataColumn column) { columns.add((DataColumnImpl) column); return this; } public DataSet removeColumn(String id) { Iterator<DataColumnImpl> it = columns.iterator(); while (it.hasNext()) { DataColumn column = it.next(); if (column.getId().equalsIgnoreCase(id)) { it.remove(); } } return this; } public boolean isEmpty() { return getRowCount() == 0; } public int getRowCount() { if (columns == null || columns.isEmpty()) { return 0; } return columns.get(0).getValues().size(); } public int getRowCountNonTrimmed() { if (rowCountNonTrimmed == -1) return getRowCount(); return rowCountNonTrimmed; } public void setRowCountNonTrimmed(int rowCountNonTrimmed) { this.rowCountNonTrimmed = rowCountNonTrimmed; } public Object getValueAt(int row, String columnId) { DataColumn columnObj = getColumnById(columnId); return getValueAt(row, columnObj); } public Object getValueAt(int row, int column) { DataColumn columnObj = getColumnByIndex(column); return getValueAt(row, columnObj); } protected Object getValueAt(int row, DataColumn column) { if (row >= getRowCount()) { throw new IllegalArgumentException("The row index " + row + " is out of bounds: " + (getRowCount()-1)); } return column.getValues().get(row); } public DataSet setValueAt(int row, int column, Object value) { _setValueAt(row, column, value, false); return this; } public DataSet addValueAt(int row, int column, Object value) { _setValueAt(row, column, value, true); return this; } public DataSet addValueAt(int column, Object value) { _setValueAt(-1, column, value, true); return this; } protected void _setValueAt(int row, int column, Object value, boolean insert) { DataColumn columnObj = getColumnByIndex(column); List l = columnObj.getValues(); if (row > l.size()) { throw new IllegalArgumentException("The row index " + row + " is out of bounds: " + (l.size()-1)); } Object _val = convert(columnObj, value); if (row < 0 || row == l.size()) l.add(_val); else if (insert) l.add(row, _val); else l.set(row, _val); } public DataSet setValuesAt(int row, Object... values) { _setValuesAt(row, false, values); return this; } public DataSet addValuesAt(int row, Object... values) { _setValuesAt(row, true, values); return this; } public DataSet addValues(Object... values) { _setValuesAt(-1, true, values); return this; } protected void _setValuesAt(int row, boolean insert, Object... values) { for (int i = 0; i < values.length; i++) { Object value = values[i]; _setValueAt(row, i, value, insert); } } public DataSet addEmptyRowAt(int row) { _setEmptyRowAt(row, true); return this; } protected void _setEmptyRowAt(int row, boolean insert) { for (int i = 0; i < columns.size(); i++) { DataColumn column = columns.get(i); if (ColumnType.DATE.equals(column.getColumnType())) { _setValueAt(row, i, new Date(), insert); } else if (ColumnType.NUMBER.equals(column.getColumnType())) { _setValueAt(row, i, 0d, insert); } else { _setValueAt(row, i, "", insert); } } } public Object convert(DataColumn column, Object value) { if (ColumnType.NUMBER.equals(column.getColumnType())) { return convertToDouble(value); } if (ColumnType.DATE.equals(column.getColumnType())) { return convertToDate(value); } return convertToString(value); } public String convertToString(Object value) { try { return value == null ? null : (String) value; } catch (ClassCastException e) { return value.toString(); } } public Double convertToDouble(Object value) { try { return value == null ? null : ((Number) value).doubleValue(); } catch (ClassCastException e) { return Double.parseDouble(value.toString()); } } public Date convertToDate(Object value) { try { return value == null ? null : (Date) value; } catch (ClassCastException e) { throw new IllegalArgumentException("Not a java.util.Date: " + value + " (" + value.getClass().getName() + ")"); } } public DataSet trim(int offset, int rows) { if (offset < 0) { throw new IllegalArgumentException("Offset can't be negative: " + offset); } if (offset == 0 && (rows <= 0 || rows >= this.getRowCount())) { this.rowCountNonTrimmed = -1; return this; } if (offset >= getRowCount()) { throw new IllegalArgumentException("Offset can't be greater than the number of rows: " + offset); } DataSetImpl other = cloneEmpty(); other.rowCountNonTrimmed = getRowCount(); for (int i=0; i<columns.size(); i++) { DataColumn column = columns.get(i); DataColumn colOther = other.getColumns().get(i); List values = column.getValues(); List valOther = colOther.getValues(); for (int j=offset; j<values.size() && j<( offset+rows ); j++) { Object value = values.get(j); valOther.add(value); } } return other; } public DataSet trim(List<Integer> rows) { if (rows == null) { return this; } DataSetImpl other = cloneEmpty(); other.rowCountNonTrimmed = getRowCount(); if (rows.isEmpty()) return other; for (int i=0; i<columns.size(); i++) { List values = columns.get(i).getValues(); List valOther = other.getColumns().get(i).getValues(); for (Integer row : rows) { if (row >= values.size()) { throw new IllegalArgumentException("Row number is out of bounds: " + row); } Object value = values.get(row); valOther.add(value); } } return other; } public DataSetImpl cloneEmpty() { DataSetImpl other = new DataSetImpl(); for (int i=0; i<columns.size(); i++) { DataColumn column = columns.get(i); DataColumn otherCol = column.cloneEmpty(); other.addColumn(otherCol); } return other; } public DataSetImpl cloneInstance() { DataSetImpl other = new DataSetImpl(); for (int i=0; i<columns.size(); i++) { DataColumn column = columns.get(i); DataColumn otherCol = column.cloneInstance(); other.addColumn(otherCol); } return other; } public boolean equals(Object obj) { try { DataSetImpl other = (DataSetImpl) obj; if (other == null) { return false; } if (getEstimatedSize() != other.getEstimatedSize()) { return false; } if (columns.size() != other.columns.size()) { return false; } for (int i=0; i<columns.size(); i++) { if (!columns.get(i).equals(other.columns.get(i))) { return false; } } return true; } catch (ClassCastException e) { return false; } } public long getEstimatedSize() { int nrows = getRowCount(); if (nrows == 0) return 0; List<DataColumn> columns = getColumns(); int ncells = nrows * columns.size(); int result = ncells * 4; for (int i = 0; i < columns.size(); i++) { Object firstRowValue = getValueAt(0, i); if (firstRowValue instanceof String) { for (int j = 0; j < nrows; j++) { String stringValue = (String) getValueAt(j, i); result += MemSizeEstimator.sizeOfString(stringValue); } } else { int singleValueSize = MemSizeEstimator.sizeOf(firstRowValue); result += nrows * singleValueSize; } } return result; } }