You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2011/04/25 11:19:32 UTC
svn commit: r1096439 [4/7] - in /incubator/isis/trunk/core/commons/src:
main/java/org/apache/isis/core/commons/authentication/
main/java/org/apache/isis/core/commons/components/
main/java/org/apache/isis/core/commons/config/ main/java/org/apache/isis/c...
Modified: incubator/isis/trunk/core/commons/src/main/java/org/apache/isis/core/commons/encoding/FieldType.java
URL: http://svn.apache.org/viewvc/incubator/isis/trunk/core/commons/src/main/java/org/apache/isis/core/commons/encoding/FieldType.java?rev=1096439&r1=1096438&r2=1096439&view=diff
==============================================================================
--- incubator/isis/trunk/core/commons/src/main/java/org/apache/isis/core/commons/encoding/FieldType.java (original)
+++ incubator/isis/trunk/core/commons/src/main/java/org/apache/isis/core/commons/encoding/FieldType.java Mon Apr 25 09:19:29 2011
@@ -17,9 +17,8 @@
* under the License.
*/
+package org.apache.isis.core.commons.encoding;
-package org.apache.isis.core.commons.encoding;
-
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
@@ -33,1353 +32,1343 @@ import java.util.HashMap;
import java.util.Map;
import org.apache.log4j.Logger;
-
-/**
- * Typesafe writing and reading of fields, providing some level of integrity
- * checking of encoded messages.
- *
- * <p>
- * The {@link #write(DataOutputExtended, Object)} writes out field type and then
- * the data for that field type. The field type is represented by this
- * enumberation, with the {@link FieldType#getIdx() index} being what is written
- * to the stream (hence of type <tt>byte</tt> to keep small).
- *
- * <p>
- * Conversely, the {@link #read(DataInputExtended)} reads the field type
- * and then the data for that field type.
- */
-public abstract class FieldType<T> {
-
- private static Logger LOG = Logger.getLogger(FieldType.class);
-
- private static String LOG_INDENT = ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ";
- private static final int NULL_BIT = 64; // 2 to the 6
-
- private static Map<Byte, FieldType<?>> cache = new HashMap<Byte, FieldType<?>>();
- private static int next=0;
-
- static enum Indenting {
- INDENT_ONLY,
- INDENT_AND_OUTDENT;
- }
-
- public static FieldType<Boolean> BOOLEAN = new FieldType<Boolean>((byte) next++, Boolean.class, Indenting.INDENT_ONLY) {
- @Override
- protected void doWrite(DataOutputExtended output, Boolean value)
- throws IOException {
- try {
- if (LOG.isDebugEnabled()) {
- log(this, new StringBuilder().append(value));
- }
- DataOutputStream outputStream = output.getDataOutputStream();
- outputStream.writeBoolean(value);
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- @Override
- protected Boolean doRead(DataInputExtended input)
- throws IOException {
- try {
- DataInputStream inputStream = input.getDataInputStream();
- boolean value = inputStream.readBoolean();
- if (LOG.isDebugEnabled()) {
- log(this, new StringBuilder().append(value));
- }
- return value;
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- };
-
- public static FieldType<boolean[]> BOOLEAN_ARRAY = new FieldType<boolean[]>((byte) next++, boolean[].class, Indenting.INDENT_AND_OUTDENT) {
- @Override
- protected void doWrite(DataOutputExtended output, boolean[] values)
- throws IOException {
- try {
- StringBuilder buf = new StringBuilder();
- DataOutputStream outputStream = output.getDataOutputStream();
- outputStream.writeInt(values.length);
- if (LOG.isDebugEnabled()) {
- buf.append("length: ").append(values.length);
- }
- for (int i = 0; i < values.length; i++) {
- outputStream.writeBoolean(values[i]);
- if (LOG.isDebugEnabled()) {
- buf.append(i==0?": ":", ");
- buf.append(values[i]);
- }
- }
- if (LOG.isDebugEnabled()) {
- log(this, buf);
- }
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- @Override
- protected boolean[] doRead(DataInputExtended input)
- throws IOException {
- try {
- StringBuilder buf = new StringBuilder();
- DataInputStream inputStream = input.getDataInputStream();
- int length = inputStream.readInt();
- if (LOG.isDebugEnabled()) {
- buf.append("length: ").append(length);
- }
- boolean[] values = new boolean[length];
- for (int i = 0; i < values.length; i++) {
- values[i] = inputStream.readBoolean();
- if (LOG.isDebugEnabled()) {
- buf.append(i==0?": ":", ");
- buf.append(values[i]);
- }
- }
- if (LOG.isDebugEnabled()) {
- log(this, buf);
- }
- return values;
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- };
-
- public static FieldType<Byte> BYTE = new FieldType<Byte>((byte) next++, Byte.class, Indenting.INDENT_ONLY) {
- @Override
- protected void doWrite(DataOutputExtended output, Byte value)
- throws IOException {
- try {
- if (LOG.isDebugEnabled()) {
- log(this, new StringBuilder().append(value));
- }
- DataOutputStream outputStream = output.getDataOutputStream();
- outputStream.writeByte(value.byteValue());
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- @Override
- protected Byte doRead(DataInputExtended input)
- throws IOException {
- try {
- DataInputStream inputStream = input.getDataInputStream();
- byte value = inputStream.readByte();
- if (LOG.isDebugEnabled()) {
- log(this, new StringBuilder().append(value));
- }
- return value;
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- };
-
- public static FieldType<byte[]> BYTE_ARRAY = new FieldType<byte[]>((byte) next++, byte[].class, Indenting.INDENT_AND_OUTDENT) {
- @Override
- protected void doWrite(DataOutputExtended output, byte[] values)
- throws IOException {
- try {
- DataOutputStream outputStream = output.getDataOutputStream();
- int length = values.length;
- outputStream.writeInt(length);
- if (LOG.isDebugEnabled()) {
- log(this, new StringBuilder().append("length:").append(length).append(" [BYTE ARRAY]"));
- }
-
- // rather than looping through the array,
- // we take advantage of optimization built into DataOutputStream
- outputStream.write(values);
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- @Override
- protected byte[] doRead(DataInputExtended input)
- throws IOException {
- try {
- DataInputStream inputStream = input.getDataInputStream();
- int length = inputStream.readInt();
- if (LOG.isDebugEnabled()) {
- StringBuilder msg = new StringBuilder().append("length:").append(length).append(" [BYTE ARRAY]");
- log(this, msg);
- }
-
- byte[] bytes = new byte[length];
- readBytes(inputStream, bytes);
- return bytes;
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
-
- // rather than looping through the array,
- // we take advantage of optimization built into DataInputStream
- @edu.umd.cs.findbugs.annotations.SuppressWarnings("RR_NOT_CHECKED")
- private void readBytes(DataInputStream inputStream, byte[] bytes) throws IOException {
- inputStream.read(bytes);
- }
- };
-
- public static FieldType<Short> SHORT = new FieldType<Short>((byte) next++, Short.class, Indenting.INDENT_ONLY) {
- @Override
- protected void doWrite(DataOutputExtended output, Short value)
- throws IOException {
- try {
- if (LOG.isDebugEnabled()) {
- log(this, new StringBuilder().append(value));
- }
- DataOutputStream outputStream = output.getDataOutputStream();
- outputStream.writeShort(value.shortValue());
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- @Override
- protected Short doRead(DataInputExtended input)
- throws IOException {
- try {
- DataInputStream inputStream = input.getDataInputStream();
- short value = inputStream.readShort();
- if (LOG.isDebugEnabled()) {
- log(this, new StringBuilder().append(value));
- }
- return value;
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- };
-
- public static FieldType<short[]> SHORT_ARRAY = new FieldType<short[]>((byte) next++, short[].class, Indenting.INDENT_AND_OUTDENT) {
- @Override
- protected void doWrite(DataOutputExtended output, short[] values)
- throws IOException {
- try {
- StringBuilder buf = new StringBuilder();
- DataOutputStream outputStream = output.getDataOutputStream();
- outputStream.writeInt(values.length);
- if (LOG.isDebugEnabled()) {
- buf.append("length: ").append(values.length);
- }
-
- for (int i = 0; i < values.length; i++) {
- outputStream.writeShort(values[i]);
- if (LOG.isDebugEnabled()) {
- buf.append(i==0?": ":", ");
- buf.append(values[i]);
- }
- }
- if (LOG.isDebugEnabled()) {
- log(this, buf);
- }
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- @Override
- protected short[] doRead(DataInputExtended input)
- throws IOException {
- try {
- StringBuilder buf = new StringBuilder();
- DataInputStream inputStream = input.getDataInputStream();
- int length = inputStream.readInt();
- if (LOG.isDebugEnabled()) {
- buf.append("length: ").append(length);
- }
-
- short[] values = new short[length];
- for (int i = 0; i < values.length; i++) {
- values[i] = inputStream.readShort();
- if (LOG.isDebugEnabled()) {
- buf.append(i==0?": ":", ");
- buf.append(values[i]);
- }
- }
- if (LOG.isDebugEnabled()) {
- log(this, buf);
- }
- return values;
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- };
-
- public static FieldType<Integer> INTEGER = new FieldType<Integer>((byte) next++, Integer.class, Indenting.INDENT_ONLY) {
- @Override
- protected void doWrite(DataOutputExtended output, Integer value)
- throws IOException {
- try {
- if (LOG.isDebugEnabled()) {
- log(this, new StringBuilder().append(value));
- }
- DataOutputStream outputStream = output.getDataOutputStream();
- outputStream.writeInt(value.intValue());
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- @Override
- protected Integer doRead(DataInputExtended input)
- throws IOException {
- try {
- DataInputStream inputStream = input.getDataInputStream();
- int value = inputStream.readInt();
- if (LOG.isDebugEnabled()) {
- log(this, new StringBuilder().append(value));
- }
- return value;
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- };
-
- public static FieldType<Integer> UNSIGNED_BYTE = new FieldType<Integer>((byte) next++, Integer.class, Indenting.INDENT_ONLY) {
- @Override
- protected void doWrite(DataOutputExtended output, Integer value)
- throws IOException {
- try {
- if (LOG.isDebugEnabled()) {
- log(this, new StringBuilder().append(value));
- }
- DataOutputStream outputStream = output.getDataOutputStream();
- outputStream.writeByte(value);
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- @Override
- protected Integer doRead(DataInputExtended input)
- throws IOException {
- try {
- DataInputStream inputStream = input.getDataInputStream();
- int value = inputStream.readUnsignedByte();
- if (LOG.isDebugEnabled()) {
- log(this, new StringBuilder().append(value));
- }
- return value;
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- };
-
- public static FieldType<Integer> UNSIGNED_SHORT = new FieldType<Integer>((byte) next++, Integer.class, Indenting.INDENT_ONLY) {
- @Override
- protected void doWrite(DataOutputExtended output, Integer value)
- throws IOException {
- try {
- if (LOG.isDebugEnabled()) {
- log(this, new StringBuilder().append(value));
- }
- DataOutputStream outputStream = output.getDataOutputStream();
- outputStream.writeShort(value);
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- @Override
- protected Integer doRead(DataInputExtended input)
- throws IOException {
- try {
- DataInputStream inputStream = input.getDataInputStream();
- int value = inputStream.readUnsignedShort();
- if (LOG.isDebugEnabled()) {
- log(this, new StringBuilder().append(value));
- }
- return value;
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- };
-
- public static FieldType<int[]> INTEGER_ARRAY = new FieldType<int[]>((byte) next++, int[].class, Indenting.INDENT_AND_OUTDENT) {
- @Override
- protected void doWrite(DataOutputExtended output, int[] values)
- throws IOException {
- try {
- StringBuilder buf = new StringBuilder();
- DataOutputStream outputStream = output.getDataOutputStream();
- outputStream.writeInt(values.length);
- if (LOG.isDebugEnabled()) {
- buf.append("length: ").append(values.length);
- }
-
- for (int i = 0; i < values.length; i++) {
- outputStream.writeInt(values[i]);
- if (LOG.isDebugEnabled()) {
- buf.append(i==0?": ":", ");
- buf.append(values[i]);
- }
- }
- if (LOG.isDebugEnabled()) {
- log(this, buf);
- }
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- @Override
- protected int[] doRead(DataInputExtended input)
- throws IOException {
- try {
- StringBuilder buf = new StringBuilder();
- DataInputStream inputStream = input.getDataInputStream();
- int length = inputStream.readInt();
- if (LOG.isDebugEnabled()) {
- buf.append("length: ").append(length);
- }
-
- int[] values = new int[length];
- for (int i = 0; i < values.length; i++) {
- values[i] = inputStream.readInt();
- if (LOG.isDebugEnabled()) {
- buf.append(i==0?": ":", ");
- buf.append(values[i]);
- }
- }
- if (LOG.isDebugEnabled()) {
- log(this, buf);
- }
- return values;
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- };
-
- public static FieldType<Long> LONG = new FieldType<Long>((byte) next++, Long.class, Indenting.INDENT_ONLY) {
- @Override
- protected void doWrite(DataOutputExtended output, Long value)
- throws IOException {
- try {
- if (LOG.isDebugEnabled()) {
- log(this, new StringBuilder().append(value));
- }
- DataOutputStream outputStream = output.getDataOutputStream();
- outputStream.writeLong(value.intValue());
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- @Override
- protected Long doRead(DataInputExtended input)
- throws IOException {
- try {
- DataInputStream inputStream = input.getDataInputStream();
- long value = inputStream.readLong();
- if (LOG.isDebugEnabled()) {
- log(this, new StringBuilder().append(value));
- }
- return value;
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- };
- public static FieldType<long[]> LONG_ARRAY = new FieldType<long[]>((byte) next++, long[].class, Indenting.INDENT_AND_OUTDENT) {
- @Override
- protected void doWrite(DataOutputExtended output, long[] values)
- throws IOException {
- try {
- StringBuilder buf = new StringBuilder();
- DataOutputStream outputStream = output.getDataOutputStream();
- outputStream.writeInt(values.length);
- if (LOG.isDebugEnabled()) {
- buf.append("length: ").append(values.length);
- }
-
- for (int i = 0; i < values.length; i++) {
- outputStream.writeLong(values[i]);
- if (LOG.isDebugEnabled()) {
- buf.append(i==0?": ":", ");
- buf.append(values[i]);
- }
- }
- if (LOG.isDebugEnabled()) {
- log(this, buf);
- }
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- @Override
- protected long[] doRead(DataInputExtended input)
- throws IOException {
- try {
- StringBuilder buf = new StringBuilder();
-
- DataInputStream inputStream = input.getDataInputStream();
- int length = inputStream.readInt();
- if (LOG.isDebugEnabled()) {
- buf.append("length: ").append(length);
- }
-
- long[] values = new long[length];
- for (int i = 0; i < values.length; i++) {
- values[i] = inputStream.readLong();
- if (LOG.isDebugEnabled()) {
- buf.append(i==0?": ":", ");
- buf.append(values[i]);
- }
- }
- if (LOG.isDebugEnabled()) {
- log(this, buf);
- }
- return values;
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- };
-
- public static FieldType<Character> CHAR = new FieldType<Character>((byte) next++, Character.class, Indenting.INDENT_ONLY) {
- @Override
- protected void doWrite(DataOutputExtended output, Character value)
- throws IOException {
- try {
- if (LOG.isDebugEnabled()) {
- log(this, new StringBuilder().append(value));
- }
- DataOutputStream outputStream = output.getDataOutputStream();
- outputStream.writeLong(value.charValue());
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- @Override
- protected Character doRead(DataInputExtended input)
- throws IOException {
- try {
- DataInputStream inputStream = input.getDataInputStream();
- char value = inputStream.readChar();
- if (LOG.isDebugEnabled()) {
- log(this, new StringBuilder().append(value));
- }
- return value;
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- };
-
- public static FieldType<char[]> CHAR_ARRAY = new FieldType<char[]>((byte) next++, char[].class, Indenting.INDENT_AND_OUTDENT) {
- // TODO: could perhaps optimize by writing out as a string
- @Override
- protected void doWrite(DataOutputExtended output, char[] values)
- throws IOException {
- try {
- StringBuilder buf = new StringBuilder();
- DataOutputStream outputStream = output.getDataOutputStream();
- outputStream.writeInt(values.length);
- if (LOG.isDebugEnabled()) {
- buf.append("length: ").append(values.length);
- }
-
- for (int i = 0; i < values.length; i++) {
- outputStream.writeChar(values[i]);
- if (LOG.isDebugEnabled()) {
- buf.append(i==0?": ":", ");
- buf.append(values[i]);
- }
- }
- if (LOG.isDebugEnabled()) {
- log(this, buf);
- }
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- @Override
- protected char[] doRead(DataInputExtended input)
- throws IOException {
- try {
- StringBuilder buf = new StringBuilder();
- DataInputStream inputStream = input.getDataInputStream();
- int length = inputStream.readInt();
- if (LOG.isDebugEnabled()) {
- buf.append("length: ").append(length);
- }
-
- char[] values = new char[length];
- for (int i = 0; i < values.length; i++) {
- if (LOG.isDebugEnabled()) {
- buf.append(i==0?": ":", ");
- buf.append(values[i]);
- }
- values[i] = inputStream.readChar();
- }
- if (LOG.isDebugEnabled()) {
- log(this, buf);
- }
- return values;
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- };
-
- public static FieldType<Float> FLOAT = new FieldType<Float>((byte) next++, Float.class, Indenting.INDENT_ONLY) {
- @Override
- protected void doWrite(DataOutputExtended output, Float value)
- throws IOException {
- try {
- if (LOG.isDebugEnabled()) {
- log(this, new StringBuilder().append(value));
- }
- DataOutputStream outputStream = output.getDataOutputStream();
- outputStream.writeFloat(value);
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- @Override
- protected Float doRead(DataInputExtended input)
- throws IOException {
- try {
- DataInputStream inputStream = input.getDataInputStream();
- float value = inputStream.readFloat();
- if (LOG.isDebugEnabled()) {
- log(this, new StringBuilder().append(value));
- }
- return value;
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- };
-
- public static FieldType<float[]> FLOAT_ARRAY = new FieldType<float[]>((byte) next++, float[].class, Indenting.INDENT_AND_OUTDENT) {
- @Override
- protected void doWrite(DataOutputExtended output, float[] values)
- throws IOException {
- try {
- StringBuilder buf = new StringBuilder();
- DataOutputStream outputStream = output.getDataOutputStream();
- outputStream.writeInt(values.length);
- if (LOG.isDebugEnabled()) {
- buf.append("length: ").append(values.length);
- }
-
- for (int i = 0; i < values.length; i++) {
- outputStream.writeFloat(values[i]);
- if (LOG.isDebugEnabled()) {
- buf.append(i==0?": ":", ");
- buf.append(values[i]);
- }
- }
- if (LOG.isDebugEnabled()) {
- log(this, buf);
- }
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- @Override
- protected float[] doRead(DataInputExtended input)
- throws IOException {
- try {
- StringBuilder buf = new StringBuilder();
- DataInputStream inputStream = input.getDataInputStream();
- int length = inputStream.readInt();
- if (LOG.isDebugEnabled()) {
- buf.append("length: ").append(length);
- }
-
- float[] values = new float[length];
- for (int i = 0; i < values.length; i++) {
- values[i] = inputStream.readFloat();
- if (LOG.isDebugEnabled()) {
- buf.append(i==0?": ":", ");
- buf.append(values[i]);
- }
- }
- if (LOG.isDebugEnabled()) {
- log(this, buf);
- }
- return values;
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- };
-
- public static FieldType<Double> DOUBLE = new FieldType<Double>((byte) next++, Double.class, Indenting.INDENT_ONLY) {
- @Override
- protected void doWrite(DataOutputExtended output, Double value)
- throws IOException {
- try {
- if (LOG.isDebugEnabled()) {
- log(this, new StringBuilder().append(value));
- }
- DataOutputStream outputStream = output.getDataOutputStream();
- outputStream.writeDouble(value);
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- @Override
- protected Double doRead(DataInputExtended input)
- throws IOException {
- try {
- DataInputStream inputStream = input.getDataInputStream();
- double value = inputStream.readDouble();
- if (LOG.isDebugEnabled()) {
- log(this, new StringBuilder().append(value));
- }
- return value;
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- };
-
- public static FieldType<double[]> DOUBLE_ARRAY = new FieldType<double[]>((byte) next++, double[].class, Indenting.INDENT_AND_OUTDENT) {
- @Override
- protected void doWrite(DataOutputExtended output, double[] values)
- throws IOException {
- try {
- StringBuilder buf = new StringBuilder();
- DataOutputStream outputStream = output.getDataOutputStream();
- outputStream.writeInt(values.length);
- if (LOG.isDebugEnabled()) {
- buf.append("length: ").append(values.length);
- }
-
- for (int i = 0; i < values.length; i++) {
- outputStream.writeDouble(values[i]);
- if (LOG.isDebugEnabled()) {
- buf.append(i==0?": ":", ");
- buf.append(values[i]);
- }
- }
- if (LOG.isDebugEnabled()) {
- log(this, buf);
- }
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- @Override
- protected double[] doRead(DataInputExtended input)
- throws IOException {
- try {
- StringBuilder buf = new StringBuilder();
- DataInputStream inputStream = input.getDataInputStream();
- int length = inputStream.readInt();
- if (LOG.isDebugEnabled()) {
- buf.append("length: ").append(length);
- }
-
- double[] values = new double[length];
- for (int i = 0; i < values.length; i++) {
- values[i] = inputStream.readDouble();
- if (LOG.isDebugEnabled()) {
- buf.append(i==0?": ":", ");
- buf.append(values[i]);
- }
- }
- if (LOG.isDebugEnabled()) {
- log(this, buf);
- }
- return values;
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- };
-
- public static FieldType<String> STRING = new FieldType<String>((byte) next++, String.class, Indenting.INDENT_ONLY) {
- @Override
- protected void doWrite(DataOutputExtended output, String value)
- throws IOException {
- try {
- if (LOG.isDebugEnabled()) {
- log(this, new StringBuilder().append(value));
- }
- DataOutputStream outputStream = output.getDataOutputStream();
- outputStream.writeUTF(value);
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- @Override
- protected String doRead(DataInputExtended input)
- throws IOException {
- try {
- DataInputStream inputStream = input.getDataInputStream();
- String value = inputStream.readUTF();
- if (LOG.isDebugEnabled()) {
- log(this, new StringBuilder().append(value));
- }
- return value;
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- };
- public static FieldType<String[]> STRING_ARRAY = new FieldType<String[]>((byte) next++, String[].class, Indenting.INDENT_AND_OUTDENT) {
- @Override
- protected void doWrite(DataOutputExtended output, String[] values)
- throws IOException {
- try {
- StringBuilder buf = new StringBuilder();
- DataOutputStream outputStream = output.getDataOutputStream();
- outputStream.writeInt(values.length);
- if (LOG.isDebugEnabled()) {
- buf.append("length: ").append(values.length);
- }
-
- for (int i = 0; i < values.length; i++) {
- // using FieldType to write out takes care of null handling
- FieldType.STRING.write(output, values[i]);
- if (LOG.isDebugEnabled()) {
- buf.append(i==0?": ":", ");
- buf.append(values[i]);
- }
- }
- if (LOG.isDebugEnabled()) {
- log(this, buf);
- }
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- @Override
- protected String[] doRead(DataInputExtended input)
- throws IOException {
- try {
- StringBuilder buf = new StringBuilder();
- DataInputStream inputStream = input.getDataInputStream();
- int length = inputStream.readInt();
- if (LOG.isDebugEnabled()) {
- buf.append("length: ").append(length);
- }
-
- String[] values = new String[length];
- for (int i = 0; i < values.length; i++) {
- // using FieldType to read in takes care of null handling
- values[i] = FieldType.STRING.read(input);
- if (LOG.isDebugEnabled()) {
- buf.append(i==0?": ":", ");
- buf.append(values[i]);
- }
- }
- if (LOG.isDebugEnabled()) {
- log(this, buf);
- }
- return values;
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- };
-
- public static FieldType<Encodable> ENCODABLE = new FieldType<Encodable>((byte) next++, Encodable.class, Indenting.INDENT_AND_OUTDENT) {
- @Override
- protected void doWrite(DataOutputExtended output, Encodable encodable) throws IOException {
- try {
- // write out class
- String className = encodable.getClass().getName();
- if (LOG.isDebugEnabled()) {
- log(this, new StringBuilder().append(className));
- }
- output.writeUTF(className);
-
- // recursively encode
- encodable.encode(output);
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- @Override
- protected Encodable doRead(DataInputExtended input) throws IOException {
- try {
- // read in class name ...
- String className = input.readUTF();
- if (LOG.isDebugEnabled()) {
- log(this, new StringBuilder().append(className));
- }
-
- Class<?> cls;
- try {
- // ...obtain constructor
- cls = Thread.currentThread().getContextClassLoader().loadClass(className);
-
- Constructor<?> constructor =
- cls.getConstructor(new Class[] { DataInputExtended.class });
-
- // recursively decode
- return (Encodable) constructor.newInstance(new Object[] { input });
- } catch (ClassNotFoundException ex) {
- throw new FailedToDecodeException(ex);
- } catch (final IllegalArgumentException ex) {
- throw new FailedToDecodeException(ex);
- } catch (final InstantiationException ex) {
- throw new FailedToDecodeException(ex);
- } catch (final IllegalAccessException ex) {
- throw new FailedToDecodeException(ex);
- } catch (final InvocationTargetException ex) {
- throw new FailedToDecodeException(ex);
- } catch (SecurityException ex) {
- throw new FailedToDecodeException(ex);
- } catch (NoSuchMethodException ex) {
- throw new FailedToDecodeException(ex);
- }
-
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- @Override
- protected boolean checksStream() {
- return false;
- }
- };
-
- public static FieldType<Encodable[]> ENCODABLE_ARRAY = new FieldType<Encodable[]>((byte) next++, Encodable[].class, Indenting.INDENT_AND_OUTDENT) {
- @Override
- protected void doWrite(DataOutputExtended output, Encodable[] values) throws IOException {
- try {
- DataOutputStream outputStream = output.getDataOutputStream();
- outputStream.writeInt(values.length);
- if (LOG.isDebugEnabled()) {
- log(this, new StringBuilder().append("length: ").append(values.length));
- }
- for (Encodable encodable : values) {
- // using FieldType to write out takes care of null handling
- FieldType.ENCODABLE.write(output, encodable);
- }
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- @SuppressWarnings("unchecked")
- @Override
- protected <Q> Q[] doReadArray(DataInputExtended input, Class<Q> elementType) throws IOException {
- try {
- DataInputStream inputStream = input.getDataInputStream();
- int length = inputStream.readInt();
- if (LOG.isDebugEnabled()) {
- log(this, new StringBuilder().append("length: ").append(length));
- }
-
- Q[] values = (Q[]) Array.newInstance(elementType, length);
- for (int i = 0; i < values.length; i++) {
- // using FieldType to read in takes care of null handling
- values[i] = (Q) FieldType.ENCODABLE.read(input);
- }
- return values;
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- @Override
- protected boolean checksStream() {
- return false;
- }
- };
-
- public static FieldType<Serializable> SERIALIZABLE = new FieldType<Serializable>((byte) next++, Serializable.class, Indenting.INDENT_ONLY) {
- @Override
- protected void doWrite(DataOutputExtended output, Serializable value) throws IOException {
- try {
- if (LOG.isDebugEnabled()) {
- log(this, new StringBuilder().append("[SERIALIZABLE]"));
- }
-
- // write out as blob of bytes
- ObjectOutputStream oos = new ObjectOutputStream(output.getDataOutputStream());
- oos.writeObject(value);
- oos.flush();
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- @Override
- protected Serializable doRead(DataInputExtended input) throws IOException {
- try {
- if (LOG.isDebugEnabled()) {
- log(this, new StringBuilder().append("[SERIALIZABLE]"));
- }
-
- // read in a blob of bytes
- ObjectInputStream ois = new ObjectInputStream(input.getDataInputStream());
- try {
- return (Serializable) ois.readObject();
- } catch (ClassNotFoundException ex) {
- throw new FailedToDeserializeException(ex);
- }
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- @Override
- protected boolean checksStream() {
- return false;
- }
- };
-
- public static FieldType<Serializable[]> SERIALIZABLE_ARRAY = new FieldType<Serializable[]>((byte) next++, Serializable[].class, Indenting.INDENT_AND_OUTDENT) {
- @Override
- protected void doWrite(DataOutputExtended output, Serializable[] values) throws IOException {
- try {
- DataOutputStream outputStream = output.getDataOutputStream();
- outputStream.writeInt(values.length);
- if (LOG.isDebugEnabled()) {
- log(this, new StringBuilder().append("length: ").append(values.length));
- }
-
- for (Serializable value : values) {
- // using FieldType to write out takes care of null handling
- FieldType.SERIALIZABLE.write(output, value);
- }
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- @SuppressWarnings("unchecked")
- protected <Q> Q[] doReadArray(DataInputExtended input, Class<Q> elementType)
- throws IOException {
- try {
- DataInputStream inputStream = input.getDataInputStream();
- int length = inputStream.readInt();
- if (LOG.isDebugEnabled()) {
- log(this, new StringBuilder().append("length: ").append(length));
- }
-
- Q[] values = (Q[]) Array.newInstance(elementType, length);
- for (int i = 0; i < values.length; i++) {
- // using FieldType to read in takes care of null handling
- values[i] = (Q) FieldType.SERIALIZABLE.read(input);
- }
- return values;
- } finally {
- if (LOG.isDebugEnabled()) {
- unlog(this);
- }
- }
- }
- @Override
- protected boolean checksStream() {
- return false;
- }
- };
-
-
-
- public static FieldType<?> get(byte idx) {
- return cache.get(idx);
- }
-
- private final byte idx;
- private final Class<T> cls;
- private final Indenting indenting;
-
- private FieldType(byte idx, Class<T> cls, Indenting indenting) {
- this.idx = idx;
- this.cls = cls;
- this.indenting = indenting;
- cache.put(idx, this);
- }
-
- public byte getIdx() {
- return idx;
- }
-
- public Class<T> getCls() {
- return cls;
- }
-
- /**
- * Whether this implementation checks ordering in the stream.
- *
- * <p>
- * Broadly, the type safe ones do, the {@link Encodable} and {@link Serializable} ones do not.
- */
- protected boolean checksStream() {
- return true;
- }
-
-
- public final T read(DataInputExtended input)
- throws IOException {
- DataInputStream inputStream = input.getDataInputStream();
- byte fieldTypeIdxAndNullability = inputStream.readByte();
-
- boolean isNull = fieldTypeIdxAndNullability >= NULL_BIT;
- byte fieldTypeIdx = (byte) (fieldTypeIdxAndNullability - (isNull ? NULL_BIT : 0));
- try {
- FieldType<?> fieldType = FieldType.get(fieldTypeIdx);
- if (fieldType.checksStream() && fieldType != this) {
- throw new IllegalStateException("Mismatch in stream: expected "
- + this + " but got " + fieldType);
- }
-
- if (isNull && LOG.isDebugEnabled()) {
- // only log if reading a null; otherwise actual value read logged later
- log(this, new StringBuilder().append("(null)"));
- }
-
- if (isNull) {
- return null;
- } else {
- return doRead(input);
- }
- } finally {
- if (isNull && LOG.isDebugEnabled()) {
- // only unlog if reading a null
- unlog(this);
- }
- }
- }
-
- public final <Q> Q[] readArray(DataInputExtended input, Class<Q> elementType)
- throws IOException {
- DataInputStream inputStream = input.getDataInputStream();
- byte fieldTypeIdxAndNullability = inputStream.readByte();
-
- boolean isNull = fieldTypeIdxAndNullability >= NULL_BIT;
- byte fieldTypeIdx = (byte) (fieldTypeIdxAndNullability - (isNull ? NULL_BIT : 0));
- try {
- FieldType<?> fieldType = FieldType.get(fieldTypeIdx);
- if (fieldType.checksStream() && fieldType != this) {
- throw new IllegalStateException("Mismatch in stream: expected "
- + this + " but got " + fieldType);
- }
-
- if (isNull && LOG.isDebugEnabled()) {
- // only log if reading a null; otherwise actual value read logged later
- log(this, new StringBuilder().append("(null)"));
- }
-
- if (isNull) {
- return null;
- } else {
- return doReadArray(input, elementType);
- }
-
- } finally {
- if (isNull && LOG.isDebugEnabled()) {
- // only unlog if reading a null
- unlog(this);
- }
- }
-
- }
-
-
- public final void write(DataOutputExtended output, T value)
- throws IOException {
- byte fieldTypeIdxAndNullability = getIdx();
- boolean isNull = value == null;
- if (isNull) {
- // set high order bit
- fieldTypeIdxAndNullability += NULL_BIT;
- }
- try {
-
- DataOutputStream outputStream = output.getDataOutputStream();
-
- outputStream.write(fieldTypeIdxAndNullability);
- if (isNull && LOG.isDebugEnabled()) {
- // only log if writing a null; otherwise actual value logged later
- log(this, new StringBuilder().append("(null)"));
- }
-
- if(!isNull) {
- doWrite(output, value);
- }
- } finally {
- if (isNull && LOG.isDebugEnabled()) {
- // only unlog if writing a null
- unlog(this);
- }
- }
- }
-
- protected T doRead(DataInputExtended input)
- throws IOException {
- throw new UnsupportedOperationException("not supported for this field type");
- }
-
- protected <Q> Q[] doReadArray(DataInputExtended input, Class<Q> elementType)
- throws IOException {
- throw new UnsupportedOperationException("not supported for this field type");
- }
-
- protected abstract void doWrite(DataOutputExtended output, T value)
- throws IOException;
-
-
- private boolean isIndentingAndOutdenting() {
- return indenting == Indenting.INDENT_AND_OUTDENT;
- }
-
- /////////////////////////////////////////////////////////
- // debugging
- /////////////////////////////////////////////////////////
-
- private static ThreadLocal<int[]> debugIndent = new ThreadLocal<int[]>();
- private static void log(FieldType<?> fieldType, StringBuilder buf) {
- buf.insert(0, ": ");
- buf.insert(0, fieldType);
- if (fieldType.isIndentingAndOutdenting()) {
- buf.insert(0, "> ");
- }
- buf.insert(0, spaces(currentDebugLevel()));
- incrementDebugLevel();
- LOG.debug(buf.toString());
- }
-
- private static void unlog(FieldType<?> fieldType) {
- unlog(fieldType, new StringBuilder());
- }
-
- private static void unlog(FieldType<?> fieldType, StringBuilder buf) {
- if (fieldType.isIndentingAndOutdenting()) {
- buf.insert(0, "< ");
- }
- decrementDebugLevel();
- if (fieldType.isIndentingAndOutdenting()) {
- buf.insert(0, spaces(currentDebugLevel()));
- LOG.debug(buf.toString());
- }
- }
-
- private static String spaces(int num) {
- return LOG_INDENT.substring(0,num);
- }
-
- private static int currentDebugLevel() {
- return debugIndent()[0];
- }
-
- private static void incrementDebugLevel() {
- int[] indentLevel = debugIndent();
- indentLevel[0]+=2;
- }
-
- private static void decrementDebugLevel() {
- int[] indentLevel = debugIndent();
- indentLevel[0]-=2;
- }
-
- private static int[] debugIndent() {
- int[] indentLevel = debugIndent.get();
- if (indentLevel == null) {
- indentLevel = new int[1];
- debugIndent.set(indentLevel);
- }
- return indentLevel;
- }
-
-
- /////////////////////////////////////////////////////////
- // toString
- /////////////////////////////////////////////////////////
-
- @Override
- public String toString() {
- return getCls().getSimpleName();
- }
-
-}
+
+/**
+ * Typesafe writing and reading of fields, providing some level of integrity checking of encoded messages.
+ *
+ * <p>
+ * The {@link #write(DataOutputExtended, Object)} writes out field type and then the data for that field type. The field
+ * type is represented by this enumberation, with the {@link FieldType#getIdx() index} being what is written to the
+ * stream (hence of type <tt>byte</tt> to keep small).
+ *
+ * <p>
+ * Conversely, the {@link #read(DataInputExtended)} reads the field type and then the data for that field type.
+ */
+public abstract class FieldType<T> {
+
+ private static Logger LOG = Logger.getLogger(FieldType.class);
+
+ private static String LOG_INDENT =
+ ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ";
+ private static final int NULL_BIT = 64; // 2 to the 6
+
+ private static Map<Byte, FieldType<?>> cache = new HashMap<Byte, FieldType<?>>();
+ private static int next = 0;
+
+ static enum Indenting {
+ INDENT_ONLY, INDENT_AND_OUTDENT;
+ }
+
+ public static FieldType<Boolean> BOOLEAN = new FieldType<Boolean>((byte) next++, Boolean.class,
+ Indenting.INDENT_ONLY) {
+ @Override
+ protected void doWrite(final DataOutputExtended output, final Boolean value) throws IOException {
+ try {
+ if (LOG.isDebugEnabled()) {
+ log(this, new StringBuilder().append(value));
+ }
+ final DataOutputStream outputStream = output.getDataOutputStream();
+ outputStream.writeBoolean(value);
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+
+ @Override
+ protected Boolean doRead(final DataInputExtended input) throws IOException {
+ try {
+ final DataInputStream inputStream = input.getDataInputStream();
+ final boolean value = inputStream.readBoolean();
+ if (LOG.isDebugEnabled()) {
+ log(this, new StringBuilder().append(value));
+ }
+ return value;
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+ };
+
+ public static FieldType<boolean[]> BOOLEAN_ARRAY = new FieldType<boolean[]>((byte) next++, boolean[].class,
+ Indenting.INDENT_AND_OUTDENT) {
+ @Override
+ protected void doWrite(final DataOutputExtended output, final boolean[] values) throws IOException {
+ try {
+ final StringBuilder buf = new StringBuilder();
+ final DataOutputStream outputStream = output.getDataOutputStream();
+ outputStream.writeInt(values.length);
+ if (LOG.isDebugEnabled()) {
+ buf.append("length: ").append(values.length);
+ }
+ for (int i = 0; i < values.length; i++) {
+ outputStream.writeBoolean(values[i]);
+ if (LOG.isDebugEnabled()) {
+ buf.append(i == 0 ? ": " : ", ");
+ buf.append(values[i]);
+ }
+ }
+ if (LOG.isDebugEnabled()) {
+ log(this, buf);
+ }
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+
+ @Override
+ protected boolean[] doRead(final DataInputExtended input) throws IOException {
+ try {
+ final StringBuilder buf = new StringBuilder();
+ final DataInputStream inputStream = input.getDataInputStream();
+ final int length = inputStream.readInt();
+ if (LOG.isDebugEnabled()) {
+ buf.append("length: ").append(length);
+ }
+ final boolean[] values = new boolean[length];
+ for (int i = 0; i < values.length; i++) {
+ values[i] = inputStream.readBoolean();
+ if (LOG.isDebugEnabled()) {
+ buf.append(i == 0 ? ": " : ", ");
+ buf.append(values[i]);
+ }
+ }
+ if (LOG.isDebugEnabled()) {
+ log(this, buf);
+ }
+ return values;
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+ };
+
+ public static FieldType<Byte> BYTE = new FieldType<Byte>((byte) next++, Byte.class, Indenting.INDENT_ONLY) {
+ @Override
+ protected void doWrite(final DataOutputExtended output, final Byte value) throws IOException {
+ try {
+ if (LOG.isDebugEnabled()) {
+ log(this, new StringBuilder().append(value));
+ }
+ final DataOutputStream outputStream = output.getDataOutputStream();
+ outputStream.writeByte(value.byteValue());
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+
+ @Override
+ protected Byte doRead(final DataInputExtended input) throws IOException {
+ try {
+ final DataInputStream inputStream = input.getDataInputStream();
+ final byte value = inputStream.readByte();
+ if (LOG.isDebugEnabled()) {
+ log(this, new StringBuilder().append(value));
+ }
+ return value;
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+ };
+
+ public static FieldType<byte[]> BYTE_ARRAY = new FieldType<byte[]>((byte) next++, byte[].class,
+ Indenting.INDENT_AND_OUTDENT) {
+ @Override
+ protected void doWrite(final DataOutputExtended output, final byte[] values) throws IOException {
+ try {
+ final DataOutputStream outputStream = output.getDataOutputStream();
+ final int length = values.length;
+ outputStream.writeInt(length);
+ if (LOG.isDebugEnabled()) {
+ log(this, new StringBuilder().append("length:").append(length).append(" [BYTE ARRAY]"));
+ }
+
+ // rather than looping through the array,
+ // we take advantage of optimization built into DataOutputStream
+ outputStream.write(values);
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+
+ @Override
+ protected byte[] doRead(final DataInputExtended input) throws IOException {
+ try {
+ final DataInputStream inputStream = input.getDataInputStream();
+ final int length = inputStream.readInt();
+ if (LOG.isDebugEnabled()) {
+ final StringBuilder msg =
+ new StringBuilder().append("length:").append(length).append(" [BYTE ARRAY]");
+ log(this, msg);
+ }
+
+ final byte[] bytes = new byte[length];
+ readBytes(inputStream, bytes);
+ return bytes;
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+
+ // rather than looping through the array,
+ // we take advantage of optimization built into DataInputStream
+ @edu.umd.cs.findbugs.annotations.SuppressWarnings("RR_NOT_CHECKED")
+ private void readBytes(final DataInputStream inputStream, final byte[] bytes) throws IOException {
+ inputStream.read(bytes);
+ }
+ };
+
+ public static FieldType<Short> SHORT = new FieldType<Short>((byte) next++, Short.class, Indenting.INDENT_ONLY) {
+ @Override
+ protected void doWrite(final DataOutputExtended output, final Short value) throws IOException {
+ try {
+ if (LOG.isDebugEnabled()) {
+ log(this, new StringBuilder().append(value));
+ }
+ final DataOutputStream outputStream = output.getDataOutputStream();
+ outputStream.writeShort(value.shortValue());
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+
+ @Override
+ protected Short doRead(final DataInputExtended input) throws IOException {
+ try {
+ final DataInputStream inputStream = input.getDataInputStream();
+ final short value = inputStream.readShort();
+ if (LOG.isDebugEnabled()) {
+ log(this, new StringBuilder().append(value));
+ }
+ return value;
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+ };
+
+ public static FieldType<short[]> SHORT_ARRAY = new FieldType<short[]>((byte) next++, short[].class,
+ Indenting.INDENT_AND_OUTDENT) {
+ @Override
+ protected void doWrite(final DataOutputExtended output, final short[] values) throws IOException {
+ try {
+ final StringBuilder buf = new StringBuilder();
+ final DataOutputStream outputStream = output.getDataOutputStream();
+ outputStream.writeInt(values.length);
+ if (LOG.isDebugEnabled()) {
+ buf.append("length: ").append(values.length);
+ }
+
+ for (int i = 0; i < values.length; i++) {
+ outputStream.writeShort(values[i]);
+ if (LOG.isDebugEnabled()) {
+ buf.append(i == 0 ? ": " : ", ");
+ buf.append(values[i]);
+ }
+ }
+ if (LOG.isDebugEnabled()) {
+ log(this, buf);
+ }
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+
+ @Override
+ protected short[] doRead(final DataInputExtended input) throws IOException {
+ try {
+ final StringBuilder buf = new StringBuilder();
+ final DataInputStream inputStream = input.getDataInputStream();
+ final int length = inputStream.readInt();
+ if (LOG.isDebugEnabled()) {
+ buf.append("length: ").append(length);
+ }
+
+ final short[] values = new short[length];
+ for (int i = 0; i < values.length; i++) {
+ values[i] = inputStream.readShort();
+ if (LOG.isDebugEnabled()) {
+ buf.append(i == 0 ? ": " : ", ");
+ buf.append(values[i]);
+ }
+ }
+ if (LOG.isDebugEnabled()) {
+ log(this, buf);
+ }
+ return values;
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+ };
+
+ public static FieldType<Integer> INTEGER = new FieldType<Integer>((byte) next++, Integer.class,
+ Indenting.INDENT_ONLY) {
+ @Override
+ protected void doWrite(final DataOutputExtended output, final Integer value) throws IOException {
+ try {
+ if (LOG.isDebugEnabled()) {
+ log(this, new StringBuilder().append(value));
+ }
+ final DataOutputStream outputStream = output.getDataOutputStream();
+ outputStream.writeInt(value.intValue());
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+
+ @Override
+ protected Integer doRead(final DataInputExtended input) throws IOException {
+ try {
+ final DataInputStream inputStream = input.getDataInputStream();
+ final int value = inputStream.readInt();
+ if (LOG.isDebugEnabled()) {
+ log(this, new StringBuilder().append(value));
+ }
+ return value;
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+ };
+
+ public static FieldType<Integer> UNSIGNED_BYTE = new FieldType<Integer>((byte) next++, Integer.class,
+ Indenting.INDENT_ONLY) {
+ @Override
+ protected void doWrite(final DataOutputExtended output, final Integer value) throws IOException {
+ try {
+ if (LOG.isDebugEnabled()) {
+ log(this, new StringBuilder().append(value));
+ }
+ final DataOutputStream outputStream = output.getDataOutputStream();
+ outputStream.writeByte(value);
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+
+ @Override
+ protected Integer doRead(final DataInputExtended input) throws IOException {
+ try {
+ final DataInputStream inputStream = input.getDataInputStream();
+ final int value = inputStream.readUnsignedByte();
+ if (LOG.isDebugEnabled()) {
+ log(this, new StringBuilder().append(value));
+ }
+ return value;
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+ };
+
+ public static FieldType<Integer> UNSIGNED_SHORT = new FieldType<Integer>((byte) next++, Integer.class,
+ Indenting.INDENT_ONLY) {
+ @Override
+ protected void doWrite(final DataOutputExtended output, final Integer value) throws IOException {
+ try {
+ if (LOG.isDebugEnabled()) {
+ log(this, new StringBuilder().append(value));
+ }
+ final DataOutputStream outputStream = output.getDataOutputStream();
+ outputStream.writeShort(value);
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+
+ @Override
+ protected Integer doRead(final DataInputExtended input) throws IOException {
+ try {
+ final DataInputStream inputStream = input.getDataInputStream();
+ final int value = inputStream.readUnsignedShort();
+ if (LOG.isDebugEnabled()) {
+ log(this, new StringBuilder().append(value));
+ }
+ return value;
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+ };
+
+ public static FieldType<int[]> INTEGER_ARRAY = new FieldType<int[]>((byte) next++, int[].class,
+ Indenting.INDENT_AND_OUTDENT) {
+ @Override
+ protected void doWrite(final DataOutputExtended output, final int[] values) throws IOException {
+ try {
+ final StringBuilder buf = new StringBuilder();
+ final DataOutputStream outputStream = output.getDataOutputStream();
+ outputStream.writeInt(values.length);
+ if (LOG.isDebugEnabled()) {
+ buf.append("length: ").append(values.length);
+ }
+
+ for (int i = 0; i < values.length; i++) {
+ outputStream.writeInt(values[i]);
+ if (LOG.isDebugEnabled()) {
+ buf.append(i == 0 ? ": " : ", ");
+ buf.append(values[i]);
+ }
+ }
+ if (LOG.isDebugEnabled()) {
+ log(this, buf);
+ }
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+
+ @Override
+ protected int[] doRead(final DataInputExtended input) throws IOException {
+ try {
+ final StringBuilder buf = new StringBuilder();
+ final DataInputStream inputStream = input.getDataInputStream();
+ final int length = inputStream.readInt();
+ if (LOG.isDebugEnabled()) {
+ buf.append("length: ").append(length);
+ }
+
+ final int[] values = new int[length];
+ for (int i = 0; i < values.length; i++) {
+ values[i] = inputStream.readInt();
+ if (LOG.isDebugEnabled()) {
+ buf.append(i == 0 ? ": " : ", ");
+ buf.append(values[i]);
+ }
+ }
+ if (LOG.isDebugEnabled()) {
+ log(this, buf);
+ }
+ return values;
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+ };
+
+ public static FieldType<Long> LONG = new FieldType<Long>((byte) next++, Long.class, Indenting.INDENT_ONLY) {
+ @Override
+ protected void doWrite(final DataOutputExtended output, final Long value) throws IOException {
+ try {
+ if (LOG.isDebugEnabled()) {
+ log(this, new StringBuilder().append(value));
+ }
+ final DataOutputStream outputStream = output.getDataOutputStream();
+ outputStream.writeLong(value.intValue());
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+
+ @Override
+ protected Long doRead(final DataInputExtended input) throws IOException {
+ try {
+ final DataInputStream inputStream = input.getDataInputStream();
+ final long value = inputStream.readLong();
+ if (LOG.isDebugEnabled()) {
+ log(this, new StringBuilder().append(value));
+ }
+ return value;
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+ };
+ public static FieldType<long[]> LONG_ARRAY = new FieldType<long[]>((byte) next++, long[].class,
+ Indenting.INDENT_AND_OUTDENT) {
+ @Override
+ protected void doWrite(final DataOutputExtended output, final long[] values) throws IOException {
+ try {
+ final StringBuilder buf = new StringBuilder();
+ final DataOutputStream outputStream = output.getDataOutputStream();
+ outputStream.writeInt(values.length);
+ if (LOG.isDebugEnabled()) {
+ buf.append("length: ").append(values.length);
+ }
+
+ for (int i = 0; i < values.length; i++) {
+ outputStream.writeLong(values[i]);
+ if (LOG.isDebugEnabled()) {
+ buf.append(i == 0 ? ": " : ", ");
+ buf.append(values[i]);
+ }
+ }
+ if (LOG.isDebugEnabled()) {
+ log(this, buf);
+ }
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+
+ @Override
+ protected long[] doRead(final DataInputExtended input) throws IOException {
+ try {
+ final StringBuilder buf = new StringBuilder();
+
+ final DataInputStream inputStream = input.getDataInputStream();
+ final int length = inputStream.readInt();
+ if (LOG.isDebugEnabled()) {
+ buf.append("length: ").append(length);
+ }
+
+ final long[] values = new long[length];
+ for (int i = 0; i < values.length; i++) {
+ values[i] = inputStream.readLong();
+ if (LOG.isDebugEnabled()) {
+ buf.append(i == 0 ? ": " : ", ");
+ buf.append(values[i]);
+ }
+ }
+ if (LOG.isDebugEnabled()) {
+ log(this, buf);
+ }
+ return values;
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+ };
+
+ public static FieldType<Character> CHAR = new FieldType<Character>((byte) next++, Character.class,
+ Indenting.INDENT_ONLY) {
+ @Override
+ protected void doWrite(final DataOutputExtended output, final Character value) throws IOException {
+ try {
+ if (LOG.isDebugEnabled()) {
+ log(this, new StringBuilder().append(value));
+ }
+ final DataOutputStream outputStream = output.getDataOutputStream();
+ outputStream.writeLong(value.charValue());
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+
+ @Override
+ protected Character doRead(final DataInputExtended input) throws IOException {
+ try {
+ final DataInputStream inputStream = input.getDataInputStream();
+ final char value = inputStream.readChar();
+ if (LOG.isDebugEnabled()) {
+ log(this, new StringBuilder().append(value));
+ }
+ return value;
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+ };
+
+ public static FieldType<char[]> CHAR_ARRAY = new FieldType<char[]>((byte) next++, char[].class,
+ Indenting.INDENT_AND_OUTDENT) {
+ // TODO: could perhaps optimize by writing out as a string
+ @Override
+ protected void doWrite(final DataOutputExtended output, final char[] values) throws IOException {
+ try {
+ final StringBuilder buf = new StringBuilder();
+ final DataOutputStream outputStream = output.getDataOutputStream();
+ outputStream.writeInt(values.length);
+ if (LOG.isDebugEnabled()) {
+ buf.append("length: ").append(values.length);
+ }
+
+ for (int i = 0; i < values.length; i++) {
+ outputStream.writeChar(values[i]);
+ if (LOG.isDebugEnabled()) {
+ buf.append(i == 0 ? ": " : ", ");
+ buf.append(values[i]);
+ }
+ }
+ if (LOG.isDebugEnabled()) {
+ log(this, buf);
+ }
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+
+ @Override
+ protected char[] doRead(final DataInputExtended input) throws IOException {
+ try {
+ final StringBuilder buf = new StringBuilder();
+ final DataInputStream inputStream = input.getDataInputStream();
+ final int length = inputStream.readInt();
+ if (LOG.isDebugEnabled()) {
+ buf.append("length: ").append(length);
+ }
+
+ final char[] values = new char[length];
+ for (int i = 0; i < values.length; i++) {
+ if (LOG.isDebugEnabled()) {
+ buf.append(i == 0 ? ": " : ", ");
+ buf.append(values[i]);
+ }
+ values[i] = inputStream.readChar();
+ }
+ if (LOG.isDebugEnabled()) {
+ log(this, buf);
+ }
+ return values;
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+ };
+
+ public static FieldType<Float> FLOAT = new FieldType<Float>((byte) next++, Float.class, Indenting.INDENT_ONLY) {
+ @Override
+ protected void doWrite(final DataOutputExtended output, final Float value) throws IOException {
+ try {
+ if (LOG.isDebugEnabled()) {
+ log(this, new StringBuilder().append(value));
+ }
+ final DataOutputStream outputStream = output.getDataOutputStream();
+ outputStream.writeFloat(value);
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+
+ @Override
+ protected Float doRead(final DataInputExtended input) throws IOException {
+ try {
+ final DataInputStream inputStream = input.getDataInputStream();
+ final float value = inputStream.readFloat();
+ if (LOG.isDebugEnabled()) {
+ log(this, new StringBuilder().append(value));
+ }
+ return value;
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+ };
+
+ public static FieldType<float[]> FLOAT_ARRAY = new FieldType<float[]>((byte) next++, float[].class,
+ Indenting.INDENT_AND_OUTDENT) {
+ @Override
+ protected void doWrite(final DataOutputExtended output, final float[] values) throws IOException {
+ try {
+ final StringBuilder buf = new StringBuilder();
+ final DataOutputStream outputStream = output.getDataOutputStream();
+ outputStream.writeInt(values.length);
+ if (LOG.isDebugEnabled()) {
+ buf.append("length: ").append(values.length);
+ }
+
+ for (int i = 0; i < values.length; i++) {
+ outputStream.writeFloat(values[i]);
+ if (LOG.isDebugEnabled()) {
+ buf.append(i == 0 ? ": " : ", ");
+ buf.append(values[i]);
+ }
+ }
+ if (LOG.isDebugEnabled()) {
+ log(this, buf);
+ }
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+
+ @Override
+ protected float[] doRead(final DataInputExtended input) throws IOException {
+ try {
+ final StringBuilder buf = new StringBuilder();
+ final DataInputStream inputStream = input.getDataInputStream();
+ final int length = inputStream.readInt();
+ if (LOG.isDebugEnabled()) {
+ buf.append("length: ").append(length);
+ }
+
+ final float[] values = new float[length];
+ for (int i = 0; i < values.length; i++) {
+ values[i] = inputStream.readFloat();
+ if (LOG.isDebugEnabled()) {
+ buf.append(i == 0 ? ": " : ", ");
+ buf.append(values[i]);
+ }
+ }
+ if (LOG.isDebugEnabled()) {
+ log(this, buf);
+ }
+ return values;
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+ };
+
+ public static FieldType<Double> DOUBLE = new FieldType<Double>((byte) next++, Double.class, Indenting.INDENT_ONLY) {
+ @Override
+ protected void doWrite(final DataOutputExtended output, final Double value) throws IOException {
+ try {
+ if (LOG.isDebugEnabled()) {
+ log(this, new StringBuilder().append(value));
+ }
+ final DataOutputStream outputStream = output.getDataOutputStream();
+ outputStream.writeDouble(value);
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+
+ @Override
+ protected Double doRead(final DataInputExtended input) throws IOException {
+ try {
+ final DataInputStream inputStream = input.getDataInputStream();
+ final double value = inputStream.readDouble();
+ if (LOG.isDebugEnabled()) {
+ log(this, new StringBuilder().append(value));
+ }
+ return value;
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+ };
+
+ public static FieldType<double[]> DOUBLE_ARRAY = new FieldType<double[]>((byte) next++, double[].class,
+ Indenting.INDENT_AND_OUTDENT) {
+ @Override
+ protected void doWrite(final DataOutputExtended output, final double[] values) throws IOException {
+ try {
+ final StringBuilder buf = new StringBuilder();
+ final DataOutputStream outputStream = output.getDataOutputStream();
+ outputStream.writeInt(values.length);
+ if (LOG.isDebugEnabled()) {
+ buf.append("length: ").append(values.length);
+ }
+
+ for (int i = 0; i < values.length; i++) {
+ outputStream.writeDouble(values[i]);
+ if (LOG.isDebugEnabled()) {
+ buf.append(i == 0 ? ": " : ", ");
+ buf.append(values[i]);
+ }
+ }
+ if (LOG.isDebugEnabled()) {
+ log(this, buf);
+ }
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+
+ @Override
+ protected double[] doRead(final DataInputExtended input) throws IOException {
+ try {
+ final StringBuilder buf = new StringBuilder();
+ final DataInputStream inputStream = input.getDataInputStream();
+ final int length = inputStream.readInt();
+ if (LOG.isDebugEnabled()) {
+ buf.append("length: ").append(length);
+ }
+
+ final double[] values = new double[length];
+ for (int i = 0; i < values.length; i++) {
+ values[i] = inputStream.readDouble();
+ if (LOG.isDebugEnabled()) {
+ buf.append(i == 0 ? ": " : ", ");
+ buf.append(values[i]);
+ }
+ }
+ if (LOG.isDebugEnabled()) {
+ log(this, buf);
+ }
+ return values;
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+ };
+
+ public static FieldType<String> STRING = new FieldType<String>((byte) next++, String.class, Indenting.INDENT_ONLY) {
+ @Override
+ protected void doWrite(final DataOutputExtended output, final String value) throws IOException {
+ try {
+ if (LOG.isDebugEnabled()) {
+ log(this, new StringBuilder().append(value));
+ }
+ final DataOutputStream outputStream = output.getDataOutputStream();
+ outputStream.writeUTF(value);
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+
+ @Override
+ protected String doRead(final DataInputExtended input) throws IOException {
+ try {
+ final DataInputStream inputStream = input.getDataInputStream();
+ final String value = inputStream.readUTF();
+ if (LOG.isDebugEnabled()) {
+ log(this, new StringBuilder().append(value));
+ }
+ return value;
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+ };
+ public static FieldType<String[]> STRING_ARRAY = new FieldType<String[]>((byte) next++, String[].class,
+ Indenting.INDENT_AND_OUTDENT) {
+ @Override
+ protected void doWrite(final DataOutputExtended output, final String[] values) throws IOException {
+ try {
+ final StringBuilder buf = new StringBuilder();
+ final DataOutputStream outputStream = output.getDataOutputStream();
+ outputStream.writeInt(values.length);
+ if (LOG.isDebugEnabled()) {
+ buf.append("length: ").append(values.length);
+ }
+
+ for (int i = 0; i < values.length; i++) {
+ // using FieldType to write out takes care of null handling
+ FieldType.STRING.write(output, values[i]);
+ if (LOG.isDebugEnabled()) {
+ buf.append(i == 0 ? ": " : ", ");
+ buf.append(values[i]);
+ }
+ }
+ if (LOG.isDebugEnabled()) {
+ log(this, buf);
+ }
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+
+ @Override
+ protected String[] doRead(final DataInputExtended input) throws IOException {
+ try {
+ final StringBuilder buf = new StringBuilder();
+ final DataInputStream inputStream = input.getDataInputStream();
+ final int length = inputStream.readInt();
+ if (LOG.isDebugEnabled()) {
+ buf.append("length: ").append(length);
+ }
+
+ final String[] values = new String[length];
+ for (int i = 0; i < values.length; i++) {
+ // using FieldType to read in takes care of null handling
+ values[i] = FieldType.STRING.read(input);
+ if (LOG.isDebugEnabled()) {
+ buf.append(i == 0 ? ": " : ", ");
+ buf.append(values[i]);
+ }
+ }
+ if (LOG.isDebugEnabled()) {
+ log(this, buf);
+ }
+ return values;
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+ };
+
+ public static FieldType<Encodable> ENCODABLE = new FieldType<Encodable>((byte) next++, Encodable.class,
+ Indenting.INDENT_AND_OUTDENT) {
+ @Override
+ protected void doWrite(final DataOutputExtended output, final Encodable encodable) throws IOException {
+ try {
+ // write out class
+ final String className = encodable.getClass().getName();
+ if (LOG.isDebugEnabled()) {
+ log(this, new StringBuilder().append(className));
+ }
+ output.writeUTF(className);
+
+ // recursively encode
+ encodable.encode(output);
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+
+ @Override
+ protected Encodable doRead(final DataInputExtended input) throws IOException {
+ try {
+ // read in class name ...
+ final String className = input.readUTF();
+ if (LOG.isDebugEnabled()) {
+ log(this, new StringBuilder().append(className));
+ }
+
+ Class<?> cls;
+ try {
+ // ...obtain constructor
+ cls = Thread.currentThread().getContextClassLoader().loadClass(className);
+
+ final Constructor<?> constructor = cls.getConstructor(new Class[] { DataInputExtended.class });
+
+ // recursively decode
+ return (Encodable) constructor.newInstance(new Object[] { input });
+ } catch (final ClassNotFoundException ex) {
+ throw new FailedToDecodeException(ex);
+ } catch (final IllegalArgumentException ex) {
+ throw new FailedToDecodeException(ex);
+ } catch (final InstantiationException ex) {
+ throw new FailedToDecodeException(ex);
+ } catch (final IllegalAccessException ex) {
+ throw new FailedToDecodeException(ex);
+ } catch (final InvocationTargetException ex) {
+ throw new FailedToDecodeException(ex);
+ } catch (final SecurityException ex) {
+ throw new FailedToDecodeException(ex);
+ } catch (final NoSuchMethodException ex) {
+ throw new FailedToDecodeException(ex);
+ }
+
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+
+ @Override
+ protected boolean checksStream() {
+ return false;
+ }
+ };
+
+ public static FieldType<Encodable[]> ENCODABLE_ARRAY = new FieldType<Encodable[]>((byte) next++, Encodable[].class,
+ Indenting.INDENT_AND_OUTDENT) {
+ @Override
+ protected void doWrite(final DataOutputExtended output, final Encodable[] values) throws IOException {
+ try {
+ final DataOutputStream outputStream = output.getDataOutputStream();
+ outputStream.writeInt(values.length);
+ if (LOG.isDebugEnabled()) {
+ log(this, new StringBuilder().append("length: ").append(values.length));
+ }
+ for (final Encodable encodable : values) {
+ // using FieldType to write out takes care of null handling
+ FieldType.ENCODABLE.write(output, encodable);
+ }
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected <Q> Q[] doReadArray(final DataInputExtended input, final Class<Q> elementType) throws IOException {
+ try {
+ final DataInputStream inputStream = input.getDataInputStream();
+ final int length = inputStream.readInt();
+ if (LOG.isDebugEnabled()) {
+ log(this, new StringBuilder().append("length: ").append(length));
+ }
+
+ final Q[] values = (Q[]) Array.newInstance(elementType, length);
+ for (int i = 0; i < values.length; i++) {
+ // using FieldType to read in takes care of null handling
+ values[i] = (Q) FieldType.ENCODABLE.read(input);
+ }
+ return values;
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+
+ @Override
+ protected boolean checksStream() {
+ return false;
+ }
+ };
+
+ public static FieldType<Serializable> SERIALIZABLE = new FieldType<Serializable>((byte) next++, Serializable.class,
+ Indenting.INDENT_ONLY) {
+ @Override
+ protected void doWrite(final DataOutputExtended output, final Serializable value) throws IOException {
+ try {
+ if (LOG.isDebugEnabled()) {
+ log(this, new StringBuilder().append("[SERIALIZABLE]"));
+ }
+
+ // write out as blob of bytes
+ final ObjectOutputStream oos = new ObjectOutputStream(output.getDataOutputStream());
+ oos.writeObject(value);
+ oos.flush();
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+
+ @Override
+ protected Serializable doRead(final DataInputExtended input) throws IOException {
+ try {
+ if (LOG.isDebugEnabled()) {
+ log(this, new StringBuilder().append("[SERIALIZABLE]"));
+ }
+
+ // read in a blob of bytes
+ final ObjectInputStream ois = new ObjectInputStream(input.getDataInputStream());
+ try {
+ return (Serializable) ois.readObject();
+ } catch (final ClassNotFoundException ex) {
+ throw new FailedToDeserializeException(ex);
+ }
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+
+ @Override
+ protected boolean checksStream() {
+ return false;
+ }
+ };
+
+ public static FieldType<Serializable[]> SERIALIZABLE_ARRAY = new FieldType<Serializable[]>((byte) next++,
+ Serializable[].class, Indenting.INDENT_AND_OUTDENT) {
+ @Override
+ protected void doWrite(final DataOutputExtended output, final Serializable[] values) throws IOException {
+ try {
+ final DataOutputStream outputStream = output.getDataOutputStream();
+ outputStream.writeInt(values.length);
+ if (LOG.isDebugEnabled()) {
+ log(this, new StringBuilder().append("length: ").append(values.length));
+ }
+
+ for (final Serializable value : values) {
+ // using FieldType to write out takes care of null handling
+ FieldType.SERIALIZABLE.write(output, value);
+ }
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ protected <Q> Q[] doReadArray(final DataInputExtended input, final Class<Q> elementType) throws IOException {
+ try {
+ final DataInputStream inputStream = input.getDataInputStream();
+ final int length = inputStream.readInt();
+ if (LOG.isDebugEnabled()) {
+ log(this, new StringBuilder().append("length: ").append(length));
+ }
+
+ final Q[] values = (Q[]) Array.newInstance(elementType, length);
+ for (int i = 0; i < values.length; i++) {
+ // using FieldType to read in takes care of null handling
+ values[i] = (Q) FieldType.SERIALIZABLE.read(input);
+ }
+ return values;
+ } finally {
+ if (LOG.isDebugEnabled()) {
+ unlog(this);
+ }
+ }
+ }
+
+ @Override
+ protected boolean checksStream() {
+ return false;
+ }
+ };
+
+ public static FieldType<?> get(final byte idx) {
+ return cache.get(idx);
+ }
+
+ private final byte idx;
+ private final Class<T> cls;
+ private final Indenting indenting;
+
+ private FieldType(final byte idx, final Class<T> cls, final Indenting indenting) {
+ this.idx = idx;
+ this.cls = cls;
+ this.indenting = indenting;
+ cache.put(idx, this);
+ }
+
+ public byte getIdx() {
+ return idx;
+ }
+
+ public Class<T> getCls() {
+ return cls;
+ }
+
+ /**
+ * Whether this implementation checks ordering in the stream.
+ *
+ * <p>
+ * Broadly, the type safe ones do, the {@link Encodable} and {@link Serializable} ones do not.
+ */
+ protected boolean checksStream() {
+ return true;
+ }
+
+ public final T read(final DataInputExtended input) throws IOException {
+ final DataInputStream inputStream = input.getDataInputStream();
+ final byte fieldTypeIdxAndNullability = inputStream.readByte();
+
+ final boolean isNull = fieldTypeIdxAndNullability >= NULL_BIT;
+ final byte fieldTypeIdx = (byte) (fieldTypeIdxAndNullability - (isNull ? NULL_BIT : 0));
+ try {
+ final FieldType<?> fieldType = FieldType.get(fieldTypeIdx);
+ if (fieldType.checksStream() && fieldType != this) {
+ throw new IllegalStateException("Mismatch in stream: expected " + this + " but got " + fieldType);
+ }
+
+ if (isNull && LOG.isDebugEnabled()) {
+ // only log if reading a null; otherwise actual value read logged later
+ log(this, new StringBuilder().append("(null)"));
+ }
+
+ if (isNull) {
+ return null;
+ } else {
+ return doRead(input);
+ }
+ } finally {
+ if (isNull && LOG.isDebugEnabled()) {
+ // only unlog if reading a null
+ unlog(this);
+ }
+ }
+ }
+
+ public final <Q> Q[] readArray(final DataInputExtended input, final Class<Q> elementType) throws IOException {
+ final DataInputStream inputStream = input.getDataInputStream();
+ final byte fieldTypeIdxAndNullability = inputStream.readByte();
+
+ final boolean isNull = fieldTypeIdxAndNullability >= NULL_BIT;
+ final byte fieldTypeIdx = (byte) (fieldTypeIdxAndNullability - (isNull ? NULL_BIT : 0));
+ try {
+ final FieldType<?> fieldType = FieldType.get(fieldTypeIdx);
+ if (fieldType.checksStream() && fieldType != this) {
+ throw new IllegalStateException("Mismatch in stream: expected " + this + " but got " + fieldType);
+ }
+
+ if (isNull && LOG.isDebugEnabled()) {
+ // only log if reading a null; otherwise actual value read logged later
+ log(this, new StringBuilder().append("(null)"));
+ }
+
+ if (isNull) {
+ return null;
+ } else {
+ return doReadArray(input, elementType);
+ }
+
+ } finally {
+ if (isNull && LOG.isDebugEnabled()) {
+ // only unlog if reading a null
+ unlog(this);
+ }
+ }
+
+ }
+
+ public final void write(final DataOutputExtended output, final T value) throws IOException {
+ byte fieldTypeIdxAndNullability = getIdx();
+ final boolean isNull = value == null;
+ if (isNull) {
+ // set high order bit
+ fieldTypeIdxAndNullability += NULL_BIT;
+ }
+ try {
+
+ final DataOutputStream outputStream = output.getDataOutputStream();
+
+ outputStream.write(fieldTypeIdxAndNullability);
+ if (isNull && LOG.isDebugEnabled()) {
+ // only log if writing a null; otherwise actual value logged later
+ log(this, new StringBuilder().append("(null)"));
+ }
+
+ if (!isNull) {
+ doWrite(output, value);
+ }
+ } finally {
+ if (isNull && LOG.isDebugEnabled()) {
+ // only unlog if writing a null
+ unlog(this);
+ }
+ }
+ }
+
+ protected T doRead(final DataInputExtended input) throws IOException {
+ throw new UnsupportedOperationException("not supported for this field type");
+ }
+
+ protected <Q> Q[] doReadArray(final DataInputExtended input, final Class<Q> elementType) throws IOException {
+ throw new UnsupportedOperationException("not supported for this field type");
+ }
+
[... 76 lines stripped ...]