/*
* This file is part of the X10 project (http://x10-lang.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* (C) Copyright IBM Corporation 2006-2012.
*/
package x10.serialization;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import x10.rtt.Types;
import x10.runtime.impl.java.Runtime;
public final class X10JavaDeserializer implements SerializationConstants {
// When a Object is deserialized record its position
private List<Object> objectList;
DataInputStream in;
private int counter = 0;
private DeserializationDictionary dict;
public X10JavaDeserializer(DataInputStream in) {
this.in = in;
objectList = new ArrayList<Object>();
dict = new DeserializationDictionary(this);
}
public DataInput getInpForHadoop() {
return in;
}
public int record_reference(Object obj) {
if (Runtime.TRACE_SER) {
String className = obj == null ? "null" : obj.getClass().getName();
Runtime.printTraceMessage("\t\tRecorded new reference of type " + Runtime.ANSI_CYAN + Runtime.ANSI_BOLD + className + Runtime.ANSI_RESET + " at " + counter + " (absolute) in map");
}
objectList.add(counter, obj);
counter++;
return counter - 1;
}
public void update_reference(int pos, Object obj) {
objectList.set(pos, obj);
}
public Object getObjectAtPosition(int pos) {
Object obj = objectList.get(pos);
if (Runtime.TRACE_SER) {
Runtime.printTraceMessage("\t\tRetrieving repeated reference of type " + Runtime.ANSI_CYAN + Runtime.ANSI_BOLD + obj.getClass().getName() + Runtime.ANSI_RESET + " at " + pos + " (absolute) in map");
}
return obj;
}
public Class<?> getClassForID(short sid) {
return dict.getClassForID(sid);
}
@SuppressWarnings("unchecked")
public <T> T readRef() throws IOException {
short serializationID = readShort();
return (T) readRef(serializationID);
}
public Object readRef(short serializationID) throws IOException {
if (serializationID == NULL_ID) {
if (Runtime.TRACE_SER) {
Runtime.printTraceMessage("Deserializing a null reference");
}
return null;
}
if (serializationID == REPEATED_OBJECT_ID) {
return getObjectAtPosition(readInt());
}
if (serializationID <= MAX_HARDCODED_ID) {
return X10JavaDeserializer.deserializePrimitive(serializationID, this);
}
if (serializationID == JAVA_ARRAY_ID) {
short componentTypeID = readShort();
if (componentTypeID == INTEGER_ID) {
return readIntArray();
} else if (componentTypeID == DOUBLE_ID) {
return readDoubleArray();
} else if (componentTypeID == FLOAT_ID) {
return readFloatArray();
} else if (componentTypeID == BOOLEAN_ID) {
return readBooleanArray();
} else if (componentTypeID == BYTE_ID) {
return readByteArray();
} else if (componentTypeID == SHORT_ID) {
return readShortArray();
} else if (componentTypeID == LONG_ID) {
return readLongArray();
} else if (componentTypeID == CHARACTER_ID) {
return readCharArray();
} else if (componentTypeID == STRING_ID) {
return readStringArray();
} else {
Class<?> componentType = getClassForID(componentTypeID);
int length = readInt();
Object obj = Array.newInstance(componentType, length);
record_reference(obj);
if (componentType.isArray()) {
for (int i = 0; i < length; ++i) {
Array.set(obj, i, readArrayUsingReflection(componentType));
}
} else {
for (int i = 0; i < length; ++i) {
Array.set(obj, i, readRefUsingReflection());
}
}
return obj;
}
}
if (Runtime.TRACE_SER) {
Runtime.printTraceMessage("Deserializing non-null value with id " + serializationID);
}
try {
Method method = dict.getMethod(serializationID);
if (method != null) {
// A class that implements X10JavaSerializable. Call _deserialize
return method.invoke(null, this);
} else {
Class<?> clazz = dict.getClassForID(serializationID);
DeserializerThunk dt = DeserializerThunk.getDeserializerThunk(clazz);
return dt.deserializeObject(clazz, this);
}
} catch (InvocationTargetException e) {
// This should never happen
throw new RuntimeException("Error in deserializing non-null value with id " + serializationID, e);
} catch (SecurityException e) {
// This should never happen
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
// This should never happen
throw new RuntimeException(e);
} catch (NoSuchFieldException e) {
// This should never happen
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
// This should never happen
throw new RuntimeException(e);
} catch (IllegalArgumentException e) {
// This should never happen
throw new RuntimeException(e);
} catch (InstantiationException e) {
// This should never happen
throw new RuntimeException(e);
}
}
@SuppressWarnings("unchecked")
public <T> void readArray(T[] array) throws IOException {
int length = array.length;
for (int i = 0; i < length; i++) {
array[i] = (T) readRef();
}
}
public int readInt() throws IOException {
int v = in.readInt();
if (Runtime.TRACE_SER) {
Runtime.printTraceMessage("Deserializing [****] an " + Runtime.ANSI_CYAN + "int" + Runtime.ANSI_RESET + ": " + v);
}
return v;
}
public int[] readIntArray() throws IOException {
int length = in.readInt();
int[] v = new int[length];
record_reference(v);
for (int i = 0; i < length; i++) {
v[i] = in.readInt();
}
return v;
}
public boolean readBoolean() throws IOException {
boolean v = in.readBoolean();
if (Runtime.TRACE_SER) {
Runtime.printTraceMessage("Deserializing [*] a " + Runtime.ANSI_CYAN + "boolean" + Runtime.ANSI_RESET + ": " + v);
}
return v;
}
public boolean[] readBooleanArray() throws IOException {
int length = in.readInt();
boolean[] v = new boolean[length];
record_reference(v);
for (int i = 0; i < length; i++) {
v[i] = in.readBoolean();
}
return v;
}
public char readChar() throws IOException {
char v = in.readChar();
if (Runtime.TRACE_SER) {
Runtime.printTraceMessage("Deserializing [**] a " + Runtime.ANSI_CYAN + "char" + Runtime.ANSI_RESET + ": " + v);
}
return v;
}
public char[] readCharArray() throws IOException {
int length = in.readInt();
char[] v = new char[length];
record_reference(v);
for (int i = 0; i < length; i++) {
v[i] = in.readChar();
}
return v;
}
public byte readByte() throws IOException {
byte v = in.readByte();
if (Runtime.TRACE_SER) {
Runtime.printTraceMessage("Deserializing [*] a " + Runtime.ANSI_CYAN + "byte" + Runtime.ANSI_RESET + ": " + v);
}
return v;
}
public byte[] readByteArray() throws IOException {
int length = in.readInt();
byte[] v = new byte[length];
record_reference(v);
_readByteArray(length, v);
return v;
}
public void _readByteArray(int length, byte[] v) throws IOException {
int read = 0;
while (read < length) {
read += in.read(v, read, length-read);
}
}
public short readShort() throws IOException {
short v = in.readShort();
if (Runtime.TRACE_SER) {
Runtime.printTraceMessage("Deserializing [**] a " + Runtime.ANSI_CYAN + "short" + Runtime.ANSI_RESET + ": " + v);
}
return v;
}
public short[] readShortArray() throws IOException {
int length = in.readInt();
short[] v = new short[length];
record_reference(v);
for (int i = 0; i < length; i++) {
v[i] = in.readShort();
}
return v;
}
public long readLong() throws IOException {
long v = in.readLong();
if (Runtime.TRACE_SER) {
Runtime.printTraceMessage("Deserializing [********] a " + Runtime.ANSI_CYAN + "long" + Runtime.ANSI_RESET + ": " + v);
}
return v;
}
public long[] readLongArray() throws IOException {
int length = in.readInt();
long[] v = new long[length];
record_reference(v);
for (int i = 0; i < length; i++) {
v[i] = in.readLong();
}
return v;
}
public double readDouble() throws IOException {
double v = in.readDouble();
if (Runtime.TRACE_SER) {
Runtime.printTraceMessage("Deserializing [********] a " + Runtime.ANSI_CYAN + "double" + Runtime.ANSI_RESET + ": " + v);
}
return v;
}
public double[] readDoubleArray() throws IOException {
int length = in.readInt();
double[] v = new double[length];
record_reference(v);
for (int i = 0; i < length; i++) {
v[i] = in.readDouble();
}
return v;
}
public float readFloat() throws IOException {
float v = in.readFloat();
if (Runtime.TRACE_SER) {
Runtime.printTraceMessage("Deserializing [****] a " + Runtime.ANSI_CYAN + "float" + Runtime.ANSI_RESET + ": " + v);
}
return v;
}
public float[] readFloatArray() throws IOException {
int length = in.readInt();
float[] v = new float[length];
record_reference(v);
for (int i = 0; i < length; i++) {
v[i] = in.readFloat();
}
return v;
}
public String readString() throws IOException {
short serializationID = readShort();
if (serializationID == NULL_ID) {
if (Runtime.TRACE_SER) {
Runtime.printTraceMessage("Deserializing a null reference");
}
return null;
}
if (serializationID == REPEATED_OBJECT_ID) {
return (String) getObjectAtPosition(readInt());
}
assert serializationID == STRING_ID;
String str = readStringValue();
if (Runtime.TRACE_SER) {
Runtime.printTraceMessage("Deserializing a " + Runtime.ANSI_CYAN + "String" + Runtime.ANSI_RESET + ": " + str);
}
record_reference(str);
return str;
}
public String readStringValue() throws IOException {
int length = readInt();
byte[] bytes = new byte[length];
_readByteArray(length, bytes);
return new String(bytes);
}
public String[] readStringArray() throws IOException {
int length = in.readInt();
String[] v = new String[length];
record_reference(v);
for (int i = 0; i < length; i++) {
v[i] = readString();
}
return v;
}
public Object readRefUsingReflection() throws IOException {
short serializationID = readShort();
if (serializationID == NULL_ID) {
if (Runtime.TRACE_SER) {
Runtime.printTraceMessage("Deserializing a null reference");
}
return null;
}
if (serializationID == REPEATED_OBJECT_ID) {
return getObjectAtPosition(readInt());
}
if (serializationID <= MAX_HARDCODED_ID) {
return X10JavaDeserializer.deserializePrimitive(serializationID, this);
}
if (Runtime.TRACE_SER) {
Runtime.printTraceMessage("Deserializing non-null value with id " + serializationID);
}
Class<?> clazz = getClassForID(serializationID);
try {
DeserializerThunk thunk = DeserializerThunk.getDeserializerThunk(clazz);
return thunk.deserializeObject(clazz, this);
} catch (SecurityException e) {
throw new RuntimeException(e);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (IllegalArgumentException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
}
}
// This method is called from generated code when an X10 class has a Java superclass.
public <T> Object deserializeClassUsingReflection(Class<? extends Object> clazz, T obj, int i) throws IOException {
try {
DeserializerThunk thunk = DeserializerThunk.getDeserializerThunk(clazz);
return thunk.deserializeObject(clazz, obj, i, this);
} catch (SecurityException e) {
throw new RuntimeException(e);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (IllegalArgumentException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
}
}
<T> void readPrimitiveUsingReflection(Field field, T obj) throws IOException, IllegalAccessException {
Class<?> type = field.getType();
if ("int".equals(type.getName())) {
field.setInt(obj, readInt());
} else if ("double".equals(type.getName())) {
field.setDouble(obj, readDouble());
} else if ("float".equals(type.getName())) {
field.setFloat(obj, readFloat());
} else if ("boolean".equals(type.getName())) {
field.setBoolean(obj, readBoolean());
} else if ("byte".equals(type.getName())) {
field.setByte(obj, readByte());
} else if ("short".equals(type.getName())) {
field.setShort(obj, readShort());
} else if ("long".equals(type.getName())) {
field.setLong(obj, readLong());
} else if ("char".equals(type.getName())) {
field.setChar(obj, readChar());
}
}
public Object readArrayUsingReflection(Class<?> componentType) throws IOException {
short serializationID = readShort();
if (serializationID == NULL_ID) {
if (Runtime.TRACE_SER) {
Runtime.printTraceMessage("Deserializing a null array");
}
return null;
}
if (serializationID == REPEATED_OBJECT_ID) {
return getObjectAtPosition(readInt());
}
if (componentType.isPrimitive()) {
if ("int".equals(componentType.getName())) {
return readIntArray();
} else if ("double".equals(componentType.getName())) {
return readDoubleArray();
} else if ("float".equals(componentType.getName())) {
return readFloatArray();
} else if ("boolean".equals(componentType.getName())) {
return readBooleanArray();
} else if ("byte".equals(componentType.getName())) {
return readByteArray();
} else if ("short".equals(componentType.getName())) {
return readShortArray();
} else if ("long".equals(componentType.getName())) {
return readLongArray();
} else if ("char".equals(componentType.getName())) {
return readCharArray();
}
} else if ("java.lang.String".equals(componentType.getName())) {
return readStringArray();
} else {
int length = readInt();
Object o = Array.newInstance(componentType, length);
record_reference(o);
if (componentType.isArray()) {
for (int i = 0; i < length; i++) {
Array.set(o, i, readArrayUsingReflection(componentType));
}
} else {
for (int i = 0; i < length; i++) {
Array.set(o, i, readRefUsingReflection());
}
}
return o;
}
return null;
}
String readStringUsingReflection() throws IOException {
return readString();
}
// Read an object using java serialization.
// This is used by IMC to optimize the serialization of primitive arrays
public Object readUsingObjectInputStream() throws IOException {
ObjectInputStream ois = new ObjectInputStream(this.in);
try {
return ois.readObject();
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
public static Object deserializePrimitive(short serializationID, X10JavaDeserializer deserializer) throws IOException {
if (Runtime.TRACE_SER) {
Runtime.printTraceMessage("Deserializing primitive/special value with id " + serializationID);
}
Object obj = null;
switch (serializationID) {
case STRING_ID:
obj = deserializer.readStringValue();
deserializer.record_reference(obj); // TODO: consider avoid recording this as a reference; it can't be cyclic.
break;
case FLOAT_ID:
obj = deserializer.readFloat();
deserializer.record_reference(obj); // TODO: consider avoid recording this as a reference; it can't be cyclic.
break;
case DOUBLE_ID:
obj = deserializer.readDouble();
deserializer.record_reference(obj); // TODO: consider avoid recording this as a reference; it can't be cyclic.
break;
case INTEGER_ID:
obj = deserializer.readInt();
deserializer.record_reference(obj); // TODO: consider avoid recording this as a reference; it can't be cyclic.
break;
case BOOLEAN_ID:
obj = deserializer.readBoolean();
deserializer.record_reference(obj); // TODO: consider avoid recording this as a reference; it can't be cyclic.
break;
case BYTE_ID:
obj = deserializer.readByte();
deserializer.record_reference(obj); // TODO: consider avoid recording this as a reference; it can't be cyclic.
break;
case SHORT_ID:
obj = deserializer.readShort();
deserializer.record_reference(obj); // TODO: consider avoid recording this as a reference; it can't be cyclic.
break;
case CHARACTER_ID:
obj = deserializer.readChar();
deserializer.record_reference(obj); // TODO: consider avoid recording this as a reference; it can't be cyclic.
break;
case LONG_ID:
obj = deserializer.readLong();
deserializer.record_reference(obj); // TODO: consider avoid recording this as a reference; it can't be cyclic.
break;
case RTT_ANY_ID:
obj = Types.ANY;
break;
case RTT_BOOLEAN_ID:
obj = Types.BOOLEAN;
break;
case RTT_BYTE_ID:
obj = Types.BYTE;
break;
case RTT_CHAR_ID:
obj = Types.CHAR;
break;
case RTT_DOUBLE_ID:
obj = Types.DOUBLE;
break;
case RTT_FLOAT_ID:
obj = Types.FLOAT;
break;
case RTT_INT_ID:
obj = Types.INT;
break;
case RTT_LONG_ID:
obj = Types.LONG;
break;
case RTT_SHORT_ID:
obj = Types.SHORT;
break;
case RTT_STRING_ID:
obj = Types.STRING;
break;
case RTT_UBYTE_ID:
obj = Types.UBYTE;
break;
case RTT_UINT_ID:
obj = Types.UINT;
break;
case RTT_ULONG_ID:
obj = Types.ULONG;
break;
case RTT_USHORT_ID:
obj = Types.USHORT;
break;
default:
throw new RuntimeException("Unhandled hard-wired serialization id in readPrimitive!");
}
return obj;
}
}