package mil.nga.giat.geowave.core.store.data.field; import java.lang.reflect.Array; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; import mil.nga.giat.geowave.core.store.data.field.ArrayWriter.Encoding; import mil.nga.giat.geowave.core.store.filter.GenericTypeResolver; /** * This class contains the basic array reader field types * */ public class ArrayReader<FieldType> implements FieldReader<FieldType[]> { private final FieldReader<FieldType> reader; public ArrayReader( final FieldReader<FieldType> reader ) { this.reader = reader; } @Override public FieldType[] readField( final byte[] fieldData ) { final byte encoding = fieldData[0]; // try to read the encoding first if (encoding == Encoding.FIXED_SIZE_ENCODING.getByteEncoding()) { return readFixedSizeField(fieldData); } else if (encoding == Encoding.VARIABLE_SIZE_ENCODING.getByteEncoding()) { return readVariableSizeField(fieldData); } // class type not supported! // to be safe, treat as variable size return readVariableSizeField(fieldData); } @SuppressWarnings("unchecked") protected FieldType[] readFixedSizeField( final byte[] fieldData ) { if (fieldData.length < 1) { return null; } final List<FieldType> result = new ArrayList<FieldType>(); final ByteBuffer buff = ByteBuffer.wrap(fieldData); // this would be bad if (buff.get() != Encoding.FIXED_SIZE_ENCODING.getByteEncoding()) { return null; } final int bytesPerEntry = buff.getInt(); final byte[] data = new byte[bytesPerEntry]; while (buff.remaining() > 0) { final int header = buff.get(); for (int i = 0; i < 8; i++) { final int mask = (int) Math.pow( 2.0, i); if ((header & mask) != 0) { if (buff.remaining() > 0) { buff.get(data); result.add(reader.readField(data)); } else { break; } } else { result.add(null); } } } final FieldType[] resultArray = (FieldType[]) Array.newInstance( GenericTypeResolver.resolveTypeArgument( reader.getClass(), FieldReader.class), result.size()); return result.toArray(resultArray); } @SuppressWarnings("unchecked") protected FieldType[] readVariableSizeField( final byte[] fieldData ) { if ((fieldData == null) || (fieldData.length < 4)) { return null; } final List<FieldType> result = new ArrayList<FieldType>(); final ByteBuffer buff = ByteBuffer.wrap(fieldData); // this would be bad if (buff.get() != Encoding.VARIABLE_SIZE_ENCODING.getByteEncoding()) { return null; } while (buff.remaining() >= 4) { final int size = buff.getInt(); if (size > 0) { final byte[] bytes = new byte[size]; buff.get(bytes); result.add(reader.readField(bytes)); } else { result.add(null); } } final FieldType[] resultArray = (FieldType[]) Array.newInstance( GenericTypeResolver.resolveTypeArgument( reader.getClass(), FieldReader.class), result.size()); return result.toArray(resultArray); } public static class FixedSizeObjectArrayReader<FieldType> extends ArrayReader<FieldType> { public FixedSizeObjectArrayReader( final FieldReader<FieldType> reader ) { super( reader); } @Override public FieldType[] readField( final byte[] fieldData ) { return readFixedSizeField(fieldData); } } public static class VariableSizeObjectArrayReader<FieldType> extends ArrayReader<FieldType> { public VariableSizeObjectArrayReader( final FieldReader<FieldType> reader ) { super( reader); } @Override public FieldType[] readField( final byte[] fieldData ) { return readVariableSizeField(fieldData); } } }