package com.tesora.dve.resultset;
/*
* #%L
* Tesora Inc.
* Database Virtualization Engine
* %%
* Copyright (C) 2011 - 2014 Tesora Inc.
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
import java.io.Serializable;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import com.tesora.dve.exceptions.PEException;
/**
* Tracks a list of <code>ResultRow</code> objects representing data going to or
* coming from a database. A <code>ResultChunk</code> can have a maximum size
* (in bytes).
*
*/
public class ResultChunk implements Serializable {
private static final long serialVersionUID = 1L;
/**
* Constant for the default result chunk size in bytes
*/
private static final String RESULT_CHUNK_MAX_SIZE_DEFAULT = "50000";
/**
* A List of ResultRow objects representing the chunk
*/
protected List<ResultRow> rowList;
/**
* The column metadata associated with this chunk of data
*/
protected ColumnSet columnSet;
/**
* The size of each ResultRow in bytes - not the size of the "Object" but
* the width of columns in aggregate
*/
protected long rowSize;
/**
* The maximum size this ResultChunk is configured to be. Can be set 3 ways:
* - The default is specified by the constant RESULT_CHUNK_MAX_SIZE_DEFAULT
* - Retrieved from properties file with prefix.ResultChunkMaxSize key -
* Overriden using the setMaxChunkSize() method
*
*
*/
protected long maxChunkSize;
/**
* Default Constructor - will not have metadata or any properties
*/
public ResultChunk() {
this.init(null);
};
/**
*
* @param cs
* A <code>ColumnSet</code> object containing the metadata for
* this chunk
* @param props
* A <Property> object
* @param prefix
* the prefix to be used when looking up items in props.
*/
public ResultChunk(ColumnSet cs, Properties props, String prefix) {
this.init(cs);
this.setMaxSize(props, prefix);
}
/**
*
* @param props
* A <Property> object
* @param prefix
* the prefix to be used when looking up items in props.
*/
public ResultChunk(Properties props, String prefix) {
setMaxSize(props, prefix);
init(null);
}
public ResultChunk(List<ResultRow> rows) {
setRowList(rows);
}
/*
* Builds a new ResultChunk comprised of the first <rowCount> rows
* from rowSource. The returned rows are removed from <rowSource>.
*/
public ResultChunk(ResultChunk rowSource, int rowCount) {
setRowList(rowSource.rowList.subList(0, rowCount));
rowSource.rowList = rowSource.rowList.subList(rowCount, rowSource.rowList.size());
}
void setMaxSize(Properties props, String prefix) {
setMaxChunkSize(Long.parseLong(props.getProperty(prefix
+ ".ResultChunkMaxSize", RESULT_CHUNK_MAX_SIZE_DEFAULT)));
}
private void init(ColumnSet cs) {
if (cs != null) {
this.rowSize = cs.calculateRowSize();
} else {
this.rowSize = 0;
}
this.rowList = new LinkedList<ResultRow>();
this.columnSet = cs;
}
/**
*
* @return long - the current max chunk size
*/
public long getMaxChunkSize() {
return maxChunkSize;
}
/**
* set the max chunk size
*
* @param maxChunkSize
*/
public void setMaxChunkSize(long maxChunkSize) {
this.maxChunkSize = maxChunkSize;
}
public long getRowSize() {
return rowSize;
}
public void setRowSize(long rowSize) {
this.rowSize = rowSize;
}
/**
* Adds a <code>ResultRow</code> to the chunk
*
* @param row
* a <code>ResultRow</code> object
*/
public ResultChunk addResultRow(ResultRow row) {
this.rowList.add(row);
return this;
}
/**
* Returns the current chunk as a List of rows
*
* @return List<ResultRow>
*/
public List<ResultRow> getRowList() {
return this.rowList;
}
/**
* Returns a single ResultColumn from the ResultChunk
*
* @param rowIndex - index of the row to get the column value from (this is 1 based)
* @param columnIndex - index of the column within the row (this is 1 based)
* @return ResultColumn
* @throws PEException
*/
public ResultColumn getSingleValue(int rowIndex, int columnIndex) throws PEException {
int zeroBasedRow = rowIndex - 1;
if ( rowIndex > size() )
throw new PEException( "Row index of " + rowIndex + " is out of range. Result Chunk has " + size() + " rows");
if ( columnIndex > columnSet.size() )
throw new PEException( "Column index of " + columnIndex + " is out of range. Result Chunk has " + columnSet.size() + " columns");
return rowList.get(zeroBasedRow).getResultColumn(columnIndex);
}
/**
* Set the current chunk. Note this will overwrite any rows already present
* in the ResultChunk.
*
* @param chunk
* LinkedList<ResultRow>
*/
public void setRowList(List<ResultRow> chunk) {
this.rowList = chunk;
}
/**
* Adds a ResultChunk to the current chunk
*
* @param chunk
* ResultChunk
*/
public void addChunk(ResultChunk chunk) {
this.rowSize = chunk.getRowSize();
this.rowList.addAll(chunk.getRowList());
}
/**
* get the number of ResultRow objects in the current chunk
*
* @return int
*/
public int size() {
return rowList.size();
}
public ColumnSet getColumnSet() {
return columnSet;
}
public void setColumnSet(ColumnSet columnSet) {
this.columnSet = columnSet;
}
/**
* Returns whether or not the current chunk has space for another row.
* Calculated based on the row size provided by the ColumnSet and the
* current maxChunkSize
*
* @return boolean
*/
public boolean hasSpace() {
if (this.maxChunkSize == 0)
return true; // no maximum size
else
return (this.maxChunkSize - ((this.size()+1) * this.rowSize)) > 0;
}
public void sort(Comparator<ResultRow> comparator) {
Collections.sort(rowList, comparator);
}
@Override
public String toString() {
return new StringBuilder().append("ResultChunk{").append("# Rows=")
.append(this.size()).append(", rowSize=").append(this.rowSize)
.append(", hasSpace=").append(this.hasSpace())
.append(", max chunk size=").append(this.maxChunkSize)
.append("}").toString();
}
}