| /*========================================================================= |
| * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved. |
| * This product is protected by U.S. and international copyright |
| * and intellectual property laws. Pivotal products are covered by |
| * one or more patents listed at http://www.pivotal.io/patents. |
| *========================================================================= |
| */ |
| package com.gemstone.gemfire.pdx.internal; |
| |
| import java.io.DataInput; |
| import java.io.DataOutput; |
| import java.io.IOException; |
| import java.nio.ByteBuffer; |
| import java.util.Date; |
| |
| import com.gemstone.gemfire.InternalGemFireException; |
| import com.gemstone.gemfire.internal.DSCODE; |
| import com.gemstone.gemfire.internal.InternalDataSerializer; |
| import com.gemstone.gemfire.internal.cache.GemFireCacheImpl; |
| import com.gemstone.gemfire.internal.i18n.LocalizedStrings; |
| import com.gemstone.gemfire.internal.tcp.ByteBufferInputStream; |
| import com.gemstone.gemfire.internal.tcp.ByteBufferInputStream.ByteSource; |
| import com.gemstone.gemfire.pdx.FieldType; |
| import com.gemstone.gemfire.pdx.PdxFieldTypeMismatchException; |
| import com.gemstone.gemfire.pdx.PdxInstance; |
| import com.gemstone.gemfire.pdx.PdxReader; |
| import com.gemstone.gemfire.pdx.PdxSerializable; |
| import com.gemstone.gemfire.pdx.PdxSerializationException; |
| import com.gemstone.gemfire.pdx.PdxSerializer; |
| import com.gemstone.gemfire.pdx.PdxUnreadFields; |
| import com.gemstone.gemfire.pdx.internal.AutoSerializableManager.AutoClassInfo; |
| import com.gemstone.gemfire.pdx.internal.AutoSerializableManager.PdxFieldWrapper; |
| |
| /** |
| * A new instance of this class is created each time we deserialize a pdx. |
| * It is also used as the base class of our {@link PdxInstance} implementation. |
| * It is serializable because PdxInstance is. |
| * |
| * @since 6.6 |
| * @see InternalDataSerializer#readPdxSerializable(java.io.DataInput) |
| */ |
| public class PdxReaderImpl implements InternalPdxReader, java.io.Serializable { |
| |
| private static final long serialVersionUID = -6094553093860427759L; |
| /** |
| * This is the type the blob we are reading was encoded with. |
| */ |
| private final PdxType blobType; |
| private final PdxInputStream dis; |
| private transient PdxUnreadData readUnreadFieldsCalled; |
| |
| protected PdxReaderImpl(PdxReaderImpl copy) { |
| this.blobType = copy.blobType; |
| this.dis = new PdxInputStream(copy.dis); |
| this.readUnreadFieldsCalled = copy.getReadUnreadFieldsCalled(); |
| } |
| |
| public PdxReaderImpl(PdxType pdxType, DataInput in, int len) throws IOException { |
| this(pdxType, createDis(in, len)); |
| } |
| private static PdxInputStream createDis(DataInput in, int len) throws IOException { |
| boolean isBBIS = in instanceof ByteBufferInputStream; |
| PdxInputStream bbis; |
| if (isBBIS) { |
| // Note, it is ok for our immutable bbis to wrap a mutable bbis |
| // because PdxReaderImpl is only used for a quick deserialization. |
| // PdxInstanceImpl has its own flavor of createDis since it can |
| // live longer. |
| bbis = new PdxInputStream((ByteBufferInputStream) in, len); |
| int bytesSkipped = in.skipBytes(len); |
| int bytesRemaining = len - bytesSkipped; |
| while (bytesRemaining > 0) { |
| in.readByte(); |
| bytesRemaining--; |
| } |
| } else { |
| byte[] bytes = new byte[len]; |
| in.readFully(bytes); |
| bbis = new PdxInputStream(bytes); |
| } |
| return bbis; |
| } |
| |
| protected PdxReaderImpl(PdxType pdxType, PdxInputStream bbis) { |
| this.blobType = pdxType; |
| this.dis = bbis; |
| } |
| |
| public static final int MAX_UNSIGNED_BYTE = 255; |
| public static final int MAX_UNSIGNED_SHORT = 65535; |
| |
| /** |
| * @return size of each variable length field offset |
| */ |
| private byte getSizeOfOffset() { |
| int size = this.dis.size(); |
| if (size <= MAX_UNSIGNED_BYTE) { |
| return DataSize.BYTE_SIZE; |
| } else if (size <= MAX_UNSIGNED_SHORT) { |
| return DataSize.SHORT_SIZE; |
| } |
| return DataSize.INTEGER_SIZE; |
| } |
| |
| public PdxField getPdxField(String fieldName) { |
| return this.blobType.getPdxField(fieldName); |
| } |
| |
| public char readChar(String fieldName) { |
| PdxField ft = blobType.getPdxField(fieldName); |
| if (ft == null) { |
| return 0; |
| } |
| if (ft.getFieldType() != FieldType.CHAR) { |
| throw new PdxFieldTypeMismatchException( |
| "Expected char field but found field of type " + ft.getTypeIdString()); |
| } |
| return readChar(ft); |
| } |
| |
| public char readChar(PdxField ft) { |
| return dis.readChar(getPositionForField(ft)); |
| } |
| public char readChar() { |
| return dis.readChar(); |
| } |
| |
| public boolean readBoolean(String fieldName) { |
| PdxField ft = blobType.getPdxField(fieldName); |
| if (ft == null) { |
| return false; |
| } |
| if (ft.getFieldType() != FieldType.BOOLEAN) { |
| throw new PdxFieldTypeMismatchException( |
| "Expected boolean field but found field of type " |
| + ft.getTypeIdString()); |
| } |
| return readBoolean(ft); |
| } |
| |
| public boolean readBoolean(PdxField ft) { |
| return dis.readBoolean(getPositionForField(ft)); |
| } |
| public boolean readBoolean() { |
| return dis.readBoolean(); |
| } |
| |
| public byte readByte(String fieldName) { |
| PdxField ft = blobType.getPdxField(fieldName); |
| if (ft == null) { |
| return 0; |
| } |
| if (ft.getFieldType() != FieldType.BYTE) { |
| throw new PdxFieldTypeMismatchException( |
| "Expected byte field but found field of type " + ft.getTypeIdString()); |
| } |
| return readByte(ft); |
| } |
| |
| public byte readByte(PdxField ft) { |
| return dis.readByte(getPositionForField(ft)); |
| } |
| public byte readByte() { |
| return dis.readByte(); |
| } |
| |
| public short readShort(String fieldName) { |
| PdxField ft = blobType.getPdxField(fieldName); |
| if (ft == null) { |
| return 0; |
| } |
| if (ft.getFieldType() != FieldType.SHORT) { |
| throw new PdxFieldTypeMismatchException( |
| "Expected short field but found field of type " |
| + ft.getTypeIdString()); |
| } |
| return readShort(ft); |
| } |
| |
| public short readShort(PdxField ft) { |
| return dis.readShort(getPositionForField(ft)); |
| } |
| public short readShort() { |
| return dis.readShort(); |
| } |
| |
| public int readInt(String fieldName) { |
| PdxField ft = blobType.getPdxField(fieldName); |
| if (ft == null) { |
| return 0; |
| } |
| if (ft.getFieldType() != FieldType.INT) { |
| throw new PdxFieldTypeMismatchException( |
| "Expected int field but found field of type " + ft.getTypeIdString()); |
| } |
| return readInt(ft); |
| } |
| |
| public int readInt(PdxField ft) { |
| return dis.readInt(getPositionForField(ft)); |
| } |
| public int readInt() { |
| return dis.readInt(); |
| } |
| |
| public long readLong(String fieldName) { |
| PdxField ft = blobType.getPdxField(fieldName); |
| if (ft == null) { |
| return 0; |
| } |
| if (ft.getFieldType() != FieldType.LONG) { |
| throw new PdxFieldTypeMismatchException( |
| "Expected long field but found field of type " + ft.getTypeIdString()); |
| } |
| return readLong(ft); |
| } |
| |
| public long readLong(PdxField ft) { |
| return dis.readLong(getPositionForField(ft)); |
| } |
| public long readLong() { |
| return dis.readLong(); |
| } |
| |
| public float readFloat(String fieldName) { |
| PdxField ft = blobType.getPdxField(fieldName); |
| if (ft == null) { |
| return 0; |
| } |
| if (ft.getFieldType() != FieldType.FLOAT) { |
| throw new PdxFieldTypeMismatchException( |
| "Expected float field but found field of type " |
| + ft.getTypeIdString()); |
| } |
| return readFloat(ft); |
| } |
| |
| public float readFloat(PdxField ft) { |
| return dis.readFloat(getPositionForField(ft)); |
| } |
| public float readFloat() { |
| return dis.readFloat(); |
| } |
| |
| public double readDouble(String fieldName) { |
| PdxField ft = blobType.getPdxField(fieldName); |
| if (ft == null) { |
| return 0; |
| } |
| if (ft.getFieldType() != FieldType.DOUBLE) { |
| throw new PdxFieldTypeMismatchException( |
| "Expected double field but found field of type " |
| + ft.getTypeIdString()); |
| } |
| return readDouble(ft); |
| } |
| |
| public double readDouble(PdxField ft) { |
| return dis.readDouble(getPositionForField(ft)); |
| } |
| public double readDouble() { |
| return dis.readDouble(); |
| } |
| |
| public Date readDate(String fieldName) { |
| PdxField ft = blobType.getPdxField(fieldName); |
| if (ft == null) { |
| return null; |
| } |
| if (ft.getFieldType() != FieldType.DATE) { |
| throw new PdxFieldTypeMismatchException( |
| "Expected Date field but found field of type " + ft.getTypeIdString()); |
| } |
| return readDate(ft); |
| } |
| |
| public Date readDate(PdxField ft) { |
| return this.dis.readDate(getPositionForField(ft)); |
| } |
| public Date readDate() { |
| return this.dis.readDate(); |
| } |
| |
| public String readString(String fieldName) { |
| PdxField ft = blobType.getPdxField(fieldName); |
| if (ft == null) { |
| return null; |
| } |
| if (ft.getFieldType() != FieldType.STRING) { |
| throw new PdxFieldTypeMismatchException( |
| "Expected String field but found field of type " |
| + ft.getTypeIdString()); |
| } |
| return readString(ft); |
| } |
| |
| public String readString(PdxField ft) { |
| return this.dis.readString(getPositionForField(ft)); |
| } |
| public String readString() { |
| return this.dis.readString(); |
| } |
| |
| public Object readObject(String fieldName) { |
| PdxField ft = blobType.getPdxField(fieldName); |
| if (ft == null) { |
| return null; |
| } |
| if (ft.getFieldType() != FieldType.OBJECT) { |
| throw new PdxFieldTypeMismatchException( |
| "Expected Object field but found field of type " |
| + ft.getTypeIdString()); |
| } |
| return readObject(ft); |
| } |
| |
| public Object readObject(PdxField ft) { |
| if (ft instanceof DefaultPdxField) { |
| return null; // default object value |
| } |
| return this.dis.readObject(getPositionForField(ft)); |
| } |
| public Object readObject() { |
| return this.dis.readObject(); |
| } |
| |
| public char[] readCharArray(String fieldName) { |
| PdxField ft = blobType.getPdxField(fieldName); |
| if (ft == null) { |
| return null; |
| } |
| if (ft.getFieldType() != FieldType.CHAR_ARRAY) { |
| throw new PdxFieldTypeMismatchException( |
| "Expected char[] field but found field of type " |
| + ft.getTypeIdString()); |
| } |
| return readCharArray(ft); |
| } |
| |
| public char[] readCharArray(PdxField ft) { |
| return this.dis.readCharArray(getPositionForField(ft)); |
| } |
| public char[] readCharArray() { |
| return this.dis.readCharArray(); |
| } |
| |
| public boolean[] readBooleanArray(String fieldName) { |
| PdxField ft = blobType.getPdxField(fieldName); |
| if (ft == null) { |
| return null; |
| } |
| if (ft.getFieldType() != FieldType.BOOLEAN_ARRAY) { |
| throw new PdxFieldTypeMismatchException( |
| "Expected boolean[] field but found field of type " |
| + ft.getTypeIdString()); |
| } |
| return readBooleanArray(ft); |
| } |
| |
| public boolean[] readBooleanArray(PdxField ft) { |
| return this.dis.readBooleanArray(getPositionForField(ft)); |
| } |
| public boolean[] readBooleanArray() { |
| return this.dis.readBooleanArray(); |
| } |
| |
| public byte[] readByteArray(String fieldName) { |
| PdxField ft = blobType.getPdxField(fieldName); |
| if (ft == null) { |
| return null; |
| } |
| if (ft.getFieldType() != FieldType.BYTE_ARRAY) { |
| throw new PdxFieldTypeMismatchException( |
| "Expected byte[] field but found field of type " |
| + ft.getTypeIdString()); |
| } |
| return readByteArray(ft); |
| } |
| |
| public byte[] readByteArray(PdxField ft) { |
| return this.dis.readByteArray(getPositionForField(ft)); |
| } |
| public byte[] readByteArray() { |
| return this.dis.readByteArray(); |
| } |
| |
| public short[] readShortArray(String fieldName) { |
| PdxField ft = blobType.getPdxField(fieldName); |
| if (ft == null) { |
| return null; |
| } |
| if (ft.getFieldType() != FieldType.SHORT_ARRAY) { |
| throw new PdxFieldTypeMismatchException( |
| "Expected short[] field but found field of type " |
| + ft.getTypeIdString()); |
| } |
| return readShortArray(ft); |
| } |
| |
| public short[] readShortArray(PdxField ft) { |
| return this.dis.readShortArray(getPositionForField(ft)); |
| } |
| public short[] readShortArray() { |
| return this.dis.readShortArray(); |
| } |
| |
| public int[] readIntArray(String fieldName) { |
| PdxField ft = blobType.getPdxField(fieldName); |
| if (ft == null) { |
| return null; |
| } |
| if (ft.getFieldType() != FieldType.INT_ARRAY) { |
| throw new PdxFieldTypeMismatchException( |
| "Expected int[] field but found field of type " |
| + ft.getTypeIdString()); |
| } |
| return readIntArray(ft); |
| } |
| |
| public int[] readIntArray(PdxField ft) { |
| return this.dis.readIntArray(getPositionForField(ft)); |
| } |
| public int[] readIntArray() { |
| return this.dis.readIntArray(); |
| } |
| |
| public long[] readLongArray(String fieldName) { |
| PdxField ft = blobType.getPdxField(fieldName); |
| if (ft == null) { |
| return null; |
| } |
| if (ft.getFieldType() != FieldType.LONG_ARRAY) { |
| throw new PdxFieldTypeMismatchException( |
| "Expected long[] field but found field of type " |
| + ft.getTypeIdString()); |
| } |
| return readLongArray(ft); |
| } |
| |
| public long[] readLongArray(PdxField ft) { |
| return this.dis.readLongArray(getPositionForField(ft)); |
| } |
| public long[] readLongArray() { |
| return this.dis.readLongArray(); |
| } |
| |
| public float[] readFloatArray(String fieldName) { |
| PdxField ft = blobType.getPdxField(fieldName); |
| if (ft == null) { |
| return null; |
| } |
| if (ft.getFieldType() != FieldType.FLOAT_ARRAY) { |
| throw new PdxFieldTypeMismatchException( |
| "Expected float[] field but found field of type " |
| + ft.getTypeIdString()); |
| } |
| return readFloatArray(ft); |
| } |
| |
| public float[] readFloatArray(PdxField ft) { |
| return this.dis.readFloatArray(getPositionForField(ft)); |
| } |
| public float[] readFloatArray() { |
| return this.dis.readFloatArray(); |
| } |
| |
| public double[] readDoubleArray(String fieldName) { |
| PdxField ft = blobType.getPdxField(fieldName); |
| if (ft == null) { |
| return null; |
| } |
| if (ft.getFieldType() != FieldType.DOUBLE_ARRAY) { |
| throw new PdxFieldTypeMismatchException( |
| "Expected double[] field but found field of type " |
| + ft.getTypeIdString()); |
| } |
| return readDoubleArray(ft); |
| } |
| |
| public double[] readDoubleArray(PdxField ft) { |
| return this.dis.readDoubleArray(getPositionForField(ft)); |
| } |
| public double[] readDoubleArray() { |
| return this.dis.readDoubleArray(); |
| } |
| |
| public String[] readStringArray(String fieldName) { |
| PdxField ft = blobType.getPdxField(fieldName); |
| if (ft == null) { |
| return null; |
| } |
| if (ft.getFieldType() != FieldType.STRING_ARRAY) { |
| throw new PdxFieldTypeMismatchException( |
| "Expected String[] field but found field of type " |
| + ft.getTypeIdString()); |
| } |
| return readStringArray(ft); |
| } |
| |
| public String[] readStringArray(PdxField ft) { |
| return this.dis.readStringArray(getPositionForField(ft)); |
| } |
| public String[] readStringArray() { |
| return this.dis.readStringArray(); |
| } |
| |
| public Object[] readObjectArray(String fieldName) { |
| PdxField ft = blobType.getPdxField(fieldName); |
| if (ft == null) { |
| return null; |
| } |
| if (ft.getFieldType() != FieldType.OBJECT_ARRAY) { |
| throw new PdxFieldTypeMismatchException( |
| "Expected Object[] field but found field of type " |
| + ft.getTypeIdString()); |
| } |
| return readObjectArray(ft); |
| } |
| public Object[] readObjectArray(PdxField ft) { |
| if (ft instanceof DefaultPdxField) { |
| return null; // default array value |
| } |
| return this.dis.readObjectArray(getPositionForField(ft)); |
| } |
| public Object[] readObjectArray() { |
| return this.dis.readObjectArray(); |
| } |
| |
| public byte[][] readArrayOfByteArrays(String fieldName) { |
| PdxField ft = blobType.getPdxField(fieldName); |
| if (ft == null) { |
| return null; |
| } |
| if (ft.getFieldType() != FieldType.ARRAY_OF_BYTE_ARRAYS) { |
| throw new PdxFieldTypeMismatchException( |
| "Expected byte[][] field but found field of type " |
| + ft.getTypeIdString()); |
| } |
| return readArrayOfByteArrays(ft); |
| } |
| |
| public byte[][] readArrayOfByteArrays(PdxField ft) { |
| return this.dis.readArrayOfByteArrays(getPositionForField(ft)); |
| } |
| public byte[][] readArrayOfByteArrays() { |
| return this.dis.readArrayOfByteArrays(); |
| } |
| |
| /** |
| * |
| * @param idx |
| * of the variable length field |
| * @return the offset to the variable length field |
| */ |
| private int getOffset(int idx) { |
| int size = this.dis.size(); |
| if (size <= MAX_UNSIGNED_BYTE) { |
| return dis.readByte(size - idx * DataSize.BYTE_SIZE) & MAX_UNSIGNED_BYTE; |
| } else if (size <= MAX_UNSIGNED_SHORT) { |
| return dis.readShort(size - idx * DataSize.SHORT_SIZE) |
| & MAX_UNSIGNED_SHORT; |
| } else { |
| return dis.readInt(size - idx * DataSize.INTEGER_SIZE); |
| } |
| } |
| |
| private int getPositionForField(PdxField ft) { |
| return getAbsolutePosition(ft); |
| } |
| |
| private int getAbsolutePosition(PdxField ft) { |
| int pos = 0; |
| int idx0 = ft.getRelativeOffset(); |
| int idx1 = ft.getVlfOffsetIndex(); |
| |
| if (ft.isVariableLengthType()) { |
| if (idx1 != -1) { |
| pos = getOffset(idx1); |
| } else { |
| pos = idx0; |
| } |
| } else { |
| if (idx0 >= 0) { |
| // index0 indicates the offset |
| pos = idx0; |
| } else if (idx1 > 0) { |
| // index1 indicates the offset no. Read the value at that offset |
| // then move backward index0 positions backward from that value. |
| pos = getOffset(idx1) + idx0; |
| } else if (idx1 == -1) { |
| // index0 indicates no position backward from last offset position |
| pos = getOffsetToVlfTable() + idx0; |
| } else { |
| throw new InternalGemFireException("idx0=" + idx0 + " idx1=" + idx1); |
| } |
| } |
| return pos; |
| } |
| |
| private int getOffsetToVlfTable() { |
| return this.dis.size() |
| - blobType.getVariableLengthFieldCount() |
| * getSizeOfOffset(); |
| } |
| |
| public boolean hasField(String fieldName) { |
| return blobType.getPdxField(fieldName) != null; |
| } |
| |
| public boolean isIdentityField(String fieldName) { |
| PdxField field = blobType.getPdxField(fieldName); |
| return field != null && field.isIdentityField(); |
| } |
| |
| public Object readField(String fieldName) { |
| PdxField ft = blobType.getPdxField(fieldName); |
| if (ft == null) { |
| return null; |
| } |
| switch (ft.getFieldType()) { |
| case CHAR: |
| return readChar(ft); |
| case BOOLEAN: |
| return readBoolean(ft); |
| case BYTE: |
| return readByte(ft); |
| case SHORT: |
| return readShort(ft); |
| case INT: |
| return readInt(ft); |
| case LONG: |
| return readLong(ft); |
| case FLOAT: |
| return readFloat(ft); |
| case DOUBLE: |
| return readDouble(ft); |
| case DATE: |
| return readDate(ft); |
| case STRING: |
| return readString(ft); |
| case OBJECT: |
| return readObject(ft); |
| case BOOLEAN_ARRAY: |
| return readBooleanArray(ft); |
| case CHAR_ARRAY: |
| return readCharArray(ft); |
| case BYTE_ARRAY: |
| return readByteArray(ft); |
| case SHORT_ARRAY: |
| return readShortArray(ft); |
| case INT_ARRAY: |
| return readIntArray(ft); |
| case LONG_ARRAY: |
| return readLongArray(ft); |
| case FLOAT_ARRAY: |
| return readFloatArray(ft); |
| case DOUBLE_ARRAY: |
| return readDoubleArray(ft); |
| case STRING_ARRAY: |
| return readStringArray(ft); |
| case OBJECT_ARRAY: |
| return readObjectArray(ft); |
| case ARRAY_OF_BYTE_ARRAYS: |
| return readArrayOfByteArrays(ft); |
| default: |
| throw new InternalGemFireException("Unhandled field type " + ft.getFieldType()); |
| } |
| } |
| |
| public static boolean TESTHOOK_TRACKREADS = false; |
| |
| public Object getObject() throws IOException, ClassNotFoundException { |
| return basicGetObject(); |
| } |
| protected Object basicGetObject() { |
| String pdxClassName = getPdxType().getClassName(); |
| Class<?> pdxClass = getPdxType().getPdxClass(); |
| { |
| AutoClassInfo ci = getPdxType().getAutoInfo(pdxClass); |
| if (ci != null) { |
| Object obj = ci.newInstance(pdxClass); |
| this.orderedDeserialize(obj, ci); |
| return obj; |
| } |
| } |
| PdxReader pdxReader = this; |
| // only create a tracking one if we might need it |
| UnreadPdxType unreadLocalPdxType = null; |
| boolean needToTrackReads = TESTHOOK_TRACKREADS; |
| GemFireCacheImpl gfc = GemFireCacheImpl.getForPdx("PDX registry is unavailable because the Cache has been closed."); |
| TypeRegistry tr = gfc.getPdxRegistry(); |
| if (!gfc.getPdxIgnoreUnreadFields()) { |
| PdxType localPdxType = tr.getExistingTypeForClass(pdxClass); |
| if (localPdxType != null) { |
| if (getPdxType().getTypeId() != localPdxType.getTypeId()) { |
| if (getPdxType().hasExtraFields(localPdxType)) { |
| // TODO: we can calculate the extra fields here |
| needToTrackReads = true; |
| } |
| } else { |
| // TODO they are the same type id so create an optimized PdxReaderImpl |
| } |
| } else { |
| // we don't know what our local type would be |
| needToTrackReads = true; |
| } |
| } |
| |
| if (needToTrackReads) { |
| unreadLocalPdxType = tr.getExistingTypeForClass(pdxClass, getPdxType().getTypeId()); |
| if (unreadLocalPdxType != null) { |
| needToTrackReads = false; |
| } else { |
| pdxReader = new TrackingPdxReaderImpl(this, tr, pdxClass); |
| } |
| } |
| |
| Object result; |
| if (PdxSerializable.class.isAssignableFrom(pdxClass)) { |
| try { |
| result = pdxClass.newInstance(); |
| } catch (Exception e) { |
| PdxSerializationException ex = new PdxSerializationException( |
| LocalizedStrings.DataSerializer_COULD_NOT_CREATE_AN_INSTANCE_OF_A_CLASS_0 |
| .toLocalizedString(pdxClassName), e); |
| throw ex; |
| } |
| ((PdxSerializable)result).fromData(pdxReader); |
| } else { |
| PdxSerializer pdxSerializer = gfc.getPdxSerializer(); |
| if (pdxSerializer != null) { |
| result = pdxSerializer.fromData(pdxClass, pdxReader); |
| if (result == null) { |
| throw new PdxSerializationException("Could not deserialize pdx because the pdx serializer's fromData returned false for a pdx of class " + pdxClassName); |
| } |
| } else { |
| throw new PdxSerializationException("Could not deserialize pdx because a PdxSerializer does not exist."); |
| } |
| } |
| { |
| PdxUnreadData ud = getReadUnreadFieldsCalled(); |
| if (ud != null) { |
| // User called PdxReader.readUnreadFields() |
| if (unreadLocalPdxType != null) { |
| if (unreadLocalPdxType.getUnreadFieldIndexes() != null) { |
| ud.initialize(unreadLocalPdxType, this); |
| } |
| } else if (needToTrackReads) { |
| ((TrackingPdxReaderImpl)pdxReader).internalReadUnreadFields(ud); |
| } |
| } else { |
| if (needToTrackReads) { |
| ud = ((TrackingPdxReaderImpl)pdxReader).internalReadUnreadFields(new PdxUnreadData()); |
| if (ud != null && !ud.isEmpty()) { |
| tr.putUnreadData(result, ud); |
| } |
| } else if (unreadLocalPdxType != null) { |
| if (unreadLocalPdxType.getUnreadFieldIndexes() != null) { |
| tr.putUnreadData(result, new PdxUnreadData(unreadLocalPdxType, this)); |
| } |
| } |
| } |
| } |
| return result; |
| } |
| |
| PdxUnreadData getReadUnreadFieldsCalled() { |
| return this.readUnreadFieldsCalled; |
| } |
| void setReadUnreadFieldsCalled(PdxUnreadData v) { |
| this.readUnreadFieldsCalled = v; |
| } |
| |
| public PdxType getPdxType() { |
| return this.blobType; |
| } |
| |
| public ByteSource getRaw(int fieldIdx) { |
| PdxField ft = getPdxType().getPdxFieldByIndex(fieldIdx); |
| if (ft == null) { |
| throw new InternalGemFireException("unknown field " + fieldIdx); |
| } |
| return getRaw(ft); |
| } |
| |
| protected ByteSource getRaw(PdxField ft) { |
| if (ft instanceof DefaultPdxField) { |
| return ((DefaultPdxField)ft).getDefaultBytes(); |
| } |
| int startOffset = getAbsolutePosition(ft); |
| int nextFieldIdx = ft.getFieldIndex()+1; |
| int endOffset; |
| if (nextFieldIdx >= getPdxType().getFieldCount()) { |
| endOffset = getOffsetToVlfTable(); |
| } else { |
| endOffset = getAbsolutePosition(getPdxType().getPdxFieldByIndex(nextFieldIdx)); |
| } |
| return this.dis.slice(startOffset, endOffset); |
| } |
| |
| public PdxUnreadFields readUnreadFields() { |
| PdxUnreadData result = new PdxUnreadData(); |
| setReadUnreadFieldsCalled(result); |
| return result; |
| } |
| |
| protected void basicSendTo(DataOutput out) throws IOException { |
| this.dis.sendTo(out); |
| } |
| |
| protected void basicSendTo(ByteBuffer bb) { |
| this.dis.sendTo(bb); |
| } |
| |
| protected int basicSize() { |
| return this.dis.size(); |
| } |
| |
| protected void basicSetBuffer(ByteBuffer bb) { |
| this.dis.setBuffer(bb); |
| } |
| |
| /** |
| * Provides optimized deserialization when a blob exactly matches |
| * the fields of the target class when using {@link AutoSerializableManager}. |
| * @param obj the target object we are deserializing into |
| * @param ci the meta information generated by the auto serializer |
| */ |
| public void orderedDeserialize(Object obj, AutoClassInfo ci) { |
| PdxReaderImpl reader = prepForOrderedReading(); |
| for (PdxFieldWrapper f: ci.getFields()) { |
| //System.out.println("DEBUG reading field=" + f.getField().getName() + " offset=" + reader.dis.position()); |
| f.orderedDeserialize(reader, obj); |
| } |
| } |
| |
| /** |
| * Return a reader that can do ordered reading. |
| */ |
| private PdxReaderImpl prepForOrderedReading() { |
| PdxReaderImpl result = this; |
| if (this.dis instanceof PdxInstanceInputStream) { |
| result = new PdxReaderImpl(this); |
| } |
| int pos = 0; |
| if (result.blobType.getFieldCount() > 0) { |
| pos = getPositionForField(result.blobType.getFields().get(0)); |
| } |
| result.dis.position(pos); |
| return result; |
| } |
| |
| /** |
| * |
| * @param field |
| * @return PdxString if field is a String otherwise invokes {@link #readField(String)} |
| */ |
| public Object readRawField(String field){ |
| PdxField ft = blobType.getPdxField(field); |
| if (ft == null) { |
| return null; |
| } |
| if (ft.getFieldType() == FieldType.STRING) { |
| return readPdxString(ft); |
| } |
| else{ |
| return readField(field); |
| } |
| } |
| |
| /** |
| * |
| * @param ft |
| * @return returns {@link PdxString} |
| */ |
| public PdxString readPdxString(PdxField ft){ |
| ByteSource buffer = dis.getBuffer(); |
| byte[] bytes = null; |
| if(buffer.hasArray()){ |
| bytes = buffer.array(); |
| } |
| else{ |
| // TODO OFFHEAP: this is going to break once we have a ByteSource that is offheap. |
| // Should we just copy the offheap ByteSource to a heap byte[] here or change |
| // PdxString to work with a ByteSource? |
| throw new IllegalStateException(); |
| } |
| int offset = getPositionForField(ft) + buffer.arrayOffset(); |
| // Do not create PdxString if the field is NULL |
| if(bytes[offset] == DSCODE.NULL || bytes[offset] == DSCODE.NULL_STRING){ |
| return null; |
| } |
| return new PdxString(bytes, offset); |
| } |
| } |