package mil.nga.giat.geowave.core.store.data.field;
import java.nio.ByteBuffer;
import mil.nga.giat.geowave.core.index.ByteArrayId;
/**
* This class contains the basic object array writer field types
*
*/
abstract public class ArrayWriter<RowType, FieldType> implements
FieldWriter<RowType, FieldType[]>
{
public static enum Encoding {
FIXED_SIZE_ENCODING(
(byte) 0),
VARIABLE_SIZE_ENCODING(
(byte) 1);
private final byte encoding;
Encoding(
final byte encoding ) {
this.encoding = encoding;
}
public byte getByteEncoding() {
return encoding;
}
}
private FieldVisibilityHandler<RowType, Object> visibilityHandler;
private FieldWriter<RowType, FieldType> writer;
public ArrayWriter(
final FieldWriter<RowType, FieldType> writer ) {
this(
writer,
null);
}
public ArrayWriter(
final FieldWriter<RowType, FieldType> writer,
final FieldVisibilityHandler<RowType, Object> visibilityHandler ) {
this.writer = writer;
this.visibilityHandler = visibilityHandler;
}
protected byte[] writeFixedSizeField(
final FieldType[] fieldValue ) {
if (fieldValue == null) {
return new byte[] {};
}
final byte[][] byteData = getBytes(fieldValue);
final ByteBuffer buf = ByteBuffer.allocate(5 + (int) Math.ceil(fieldValue.length / 8.0) + getLength(byteData));
// this is a header value to indicate how data should be read/written
buf.put(Encoding.FIXED_SIZE_ENCODING.getByteEncoding());
int bytesPerEntry = 0;
for (final byte[] bytes : byteData) {
if (bytes.length > 0) {
bytesPerEntry = bytes.length;
}
}
// this is a header value to indicate the size of each entry
buf.putInt(bytesPerEntry);
for (int i = 0; i < fieldValue.length; i += 8) {
int header = 255;
final int headerIdx = buf.position();
buf.position(headerIdx + 1);
for (int j = 0; ((i + j) < fieldValue.length) && (j < 8); j++) {
final int mask = ~((int) Math.pow(
2.0,
j));
if (fieldValue[i + j] == null) {
header = header & mask;
}
else {
buf.put(byteData[i + j]);
}
}
buf.put(
headerIdx,
(byte) header);
}
return buf.array();
}
protected byte[] writeVariableSizeField(
final FieldType[] fieldValue ) {
if (fieldValue == null) {
return new byte[] {};
}
final byte[][] bytes = getBytes(fieldValue);
final ByteBuffer buf = ByteBuffer.allocate(1 + (4 * fieldValue.length) + getLength(bytes));
// this is a header value to indicate how data should be read/written
buf.put(Encoding.VARIABLE_SIZE_ENCODING.getByteEncoding());
for (final byte[] entry : bytes) {
buf.putInt(entry.length);
if (entry.length > 0) {
buf.put(entry);
}
}
return buf.array();
}
@Override
public byte[] getVisibility(
final RowType rowValue,
final ByteArrayId fieldId,
final FieldType[] fieldValue ) {
if (visibilityHandler != null) {
return visibilityHandler.getVisibility(
rowValue,
fieldId,
fieldValue);
}
return new byte[] {};
}
private byte[][] getBytes(
final FieldType[] fieldData ) {
final byte[][] bytes = new byte[fieldData.length][];
for (int i = 0; i < fieldData.length; i++) {
if (fieldData[i] == null) {
bytes[i] = new byte[] {};
}
else {
bytes[i] = writer.writeField(fieldData[i]);
}
}
return bytes;
}
private int getLength(
final byte[][] bytes ) {
int length = 0;
for (final byte[] entry : bytes) {
length += entry.length;
}
return length;
}
public static class FixedSizeObjectArrayWriter<RowType, FieldType> extends
ArrayWriter<RowType, FieldType>
{
public FixedSizeObjectArrayWriter(
final FieldWriter<RowType, FieldType> writer ) {
super(
writer);
}
public FixedSizeObjectArrayWriter(
final FieldWriter<RowType, FieldType> writer,
final FieldVisibilityHandler<RowType, Object> visibilityHandler ) {
super(
writer,
visibilityHandler);
}
@Override
public byte[] writeField(
final FieldType[] fieldValue ) {
return super.writeFixedSizeField(fieldValue);
}
}
public static class VariableSizeObjectArrayWriter<RowType, FieldType> extends
ArrayWriter<RowType, FieldType>
{
public VariableSizeObjectArrayWriter(
final FieldWriter<RowType, FieldType> writer ) {
super(
writer);
}
public VariableSizeObjectArrayWriter(
final FieldWriter<RowType, FieldType> writer,
final FieldVisibilityHandler<RowType, Object> visibilityHandler ) {
super(
writer,
visibilityHandler);
}
@Override
public byte[] writeField(
final FieldType[] fieldValue ) {
return super.writeVariableSizeField(fieldValue);
}
}
}