| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more contributor license |
| * agreements. See the NOTICE file distributed with this work for additional information regarding |
| * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance with the License. You may obtain a |
| * copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software distributed under the License |
| * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
| * or implied. See the License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| package org.apache.geode.pdx.internal; |
| |
| import java.io.DataInput; |
| import java.io.DataOutput; |
| import java.io.IOException; |
| import java.io.PrintStream; |
| |
| import org.apache.geode.DataSerializable; |
| import org.apache.geode.DataSerializer; |
| import org.apache.geode.internal.InternalDataSerializer; |
| import org.apache.geode.internal.serialization.Version; |
| import org.apache.geode.pdx.FieldType; |
| |
| public class PdxField implements DataSerializable, Comparable<PdxField> { |
| |
| private static final long serialVersionUID = -1095459461236458274L; |
| |
| private String fieldName; |
| private int fieldIndex; |
| private int varLenFieldSeqId; |
| private FieldType type; |
| /** |
| * If >= 0 then it is relative to the first byte of field data. Otherwise it is relative to the |
| * base determined by vlfOffsetIndex. |
| */ |
| private int relativeOffset; |
| |
| /** |
| * if >= 0 then it is the index of the vlfOffsets that this field should use as its base to find |
| * its data. If < 0 then it should be -1 which means the base is the first byte after the last |
| * byte of field data. |
| */ |
| private int vlfOffsetIndex; |
| |
| private boolean identityField; |
| |
| /** |
| * Set to true by the pdx delete-field gfsh command |
| * |
| * @since GemFire 8.1 |
| */ |
| private boolean deleted; |
| |
| public PdxField() {} |
| |
| public PdxField(String fieldName, int index, int varId, FieldType type, boolean identityField) { |
| this.fieldName = fieldName; |
| this.fieldIndex = index; |
| this.varLenFieldSeqId = varId; |
| this.type = type; |
| this.identityField = identityField; |
| } |
| |
| /** |
| * Used by {@link PdxInstanceImpl#equals(Object)} to act as if it has a field whose value is |
| * always the default. |
| */ |
| protected PdxField(PdxField other) { |
| this.fieldName = other.fieldName; |
| this.fieldIndex = other.fieldIndex; |
| this.varLenFieldSeqId = other.varLenFieldSeqId; |
| this.type = other.type; |
| this.identityField = other.identityField; |
| this.deleted = other.deleted; |
| } |
| |
| public String getFieldName() { |
| return this.fieldName; |
| } |
| |
| public int getFieldIndex() { |
| return this.fieldIndex; |
| } |
| |
| public int getVarLenFieldSeqId() { |
| return this.varLenFieldSeqId; |
| } |
| |
| public boolean isVariableLengthType() { |
| return !this.type.isFixedWidth(); |
| } |
| |
| public FieldType getFieldType() { |
| return this.type; |
| } |
| |
| public int getRelativeOffset() { |
| return this.relativeOffset; |
| } |
| |
| public void setRelativeOffset(int relativeOffset) { |
| this.relativeOffset = relativeOffset; |
| } |
| |
| public int getVlfOffsetIndex() { |
| return this.vlfOffsetIndex; |
| } |
| |
| public void setVlfOffsetIndex(int vlfOffsetIndex) { |
| this.vlfOffsetIndex = vlfOffsetIndex; |
| } |
| |
| public void setIdentityField(boolean identityField) { |
| this.identityField = identityField; |
| } |
| |
| public boolean isIdentityField() { |
| return this.identityField; |
| } |
| |
| public void setDeleted(boolean v) { |
| this.deleted = v; |
| } |
| |
| public boolean isDeleted() { |
| return this.deleted; |
| } |
| |
| private static final byte IDENTITY_BIT = 1; |
| private static final byte DELETED_BIT = 2; |
| |
| @Override |
| public void fromData(DataInput in) throws IOException, ClassNotFoundException { |
| this.fieldName = DataSerializer.readString(in); |
| this.fieldIndex = in.readInt(); |
| this.varLenFieldSeqId = in.readInt(); |
| this.type = DataSerializer.readEnum(FieldType.class, in); |
| this.relativeOffset = in.readInt(); |
| this.vlfOffsetIndex = in.readInt(); |
| { |
| byte bits = in.readByte(); |
| this.identityField = (bits & IDENTITY_BIT) != 0; |
| this.deleted = (bits & DELETED_BIT) != 0; |
| } |
| } |
| |
| @Override |
| public void toData(DataOutput out) throws IOException { |
| DataSerializer.writeString(this.fieldName, out); |
| out.writeInt(this.fieldIndex); |
| out.writeInt(this.varLenFieldSeqId); |
| DataSerializer.writeEnum(this.type, out); |
| out.writeInt(this.relativeOffset); |
| out.writeInt(this.vlfOffsetIndex); |
| { |
| // pre 8.1 we wrote a single boolean |
| // 8.1 and after we write a byte whose bits are: |
| // 1: identityField |
| // 2: deleted |
| byte bits = 0; |
| if (this.identityField) { |
| bits |= IDENTITY_BIT; |
| } |
| // Note that this code attempts to only set the DELETED_BIT |
| // if serializing for 8.1 or later. |
| // But in some cases 8.1 serialized data may be sent to a pre 8.1 member. |
| // In that case if this bit is set it will cause the pre 8.1 member |
| // to set identityField to true. |
| // For this reason the pdx delete-field command should only be used after |
| // all member have been upgraded to 8.1 or later. |
| Version sourceVersion = InternalDataSerializer.getVersionForDataStream(out); |
| if (sourceVersion.compareTo(Version.GFE_81) >= 0) { |
| if (this.deleted) { |
| bits |= DELETED_BIT; |
| } |
| } |
| out.writeByte(bits); |
| } |
| } |
| |
| @Override |
| public int hashCode() { |
| int hash = 1; |
| if (fieldName != null) { |
| hash = hash * 31 + fieldName.hashCode(); |
| } |
| if (type != null) { |
| hash = hash * 31 + type.hashCode(); |
| } |
| |
| return hash; |
| } |
| |
| // We don't compare the offsets here, because |
| // this method is to see if two different PDXTypes |
| // have equivalent fields. See PdxReaderImpl.equals. |
| @Override |
| public boolean equals(Object other) { |
| if (other == this) { |
| return true; |
| } |
| if (other == null || !(other instanceof PdxField)) { |
| return false; |
| } |
| PdxField otherVFT = (PdxField) other; |
| |
| if (otherVFT.fieldName == null) { |
| return false; |
| } |
| |
| if (otherVFT.fieldName.equals(this.fieldName) && this.isDeleted() == otherVFT.isDeleted() |
| && this.type.equals(otherVFT.type)) { |
| return true; |
| } |
| return false; |
| } |
| |
| @Override |
| public String toString() { |
| return this.fieldName + ":" + this.type + (isDeleted() ? ":DELETED" : "") |
| + (isIdentityField() ? ":identity" : "") + ":" + this.fieldIndex |
| + ((this.varLenFieldSeqId > 0) ? (":" + this.varLenFieldSeqId) : "") |
| + ":idx0(relativeOffset)=" + this.relativeOffset + ":idx1(vlfOffsetIndex)=" |
| + this.vlfOffsetIndex; |
| } |
| |
| public String getTypeIdString() { |
| return getFieldType().toString(); |
| } |
| |
| @Override |
| public int compareTo(PdxField o) { |
| return getFieldName().compareTo(o.getFieldName()); |
| } |
| |
| public void toStream(PrintStream printStream) { |
| printStream.print(" "); |
| printStream.print(getFieldType()); |
| printStream.print(' '); |
| printStream.print(this.getFieldName()); |
| printStream.print(';'); |
| if (isIdentityField()) { |
| printStream.print(" // identity"); |
| } |
| if (isDeleted()) { |
| printStream.print(" // DELETED"); |
| } |
| |
| printStream.println(); |
| } |
| } |