| /** |
| * 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.apex.malhar.lib.appdata.gpo; |
| |
| import java.io.Serializable; |
| |
| import java.util.Arrays; |
| |
| import org.apache.apex.malhar.lib.appdata.schemas.Fields; |
| import org.apache.apex.malhar.lib.appdata.schemas.FieldsDescriptor; |
| import org.apache.apex.malhar.lib.appdata.schemas.Type; |
| |
| import com.google.common.base.Preconditions; |
| |
| /** |
| * {@link GPOMutable} is an object which stores primitive fields. |
| * Each field has a primitive value stored in a primitive array and a name. |
| * Fields of a particular primitive type are stored in the same array. The order of fields |
| * in the array is the same as the lexicographic ordering of the field names. |
| * @since 3.0.0 |
| */ |
| public class GPOMutable implements Serializable |
| { |
| private static final long serialVersionUID = 201503231207L; |
| |
| //Primitive arrays holding primitive values |
| private boolean[] fieldsBoolean; |
| private char[] fieldsCharacter; |
| |
| private byte[] fieldsByte; |
| private short[] fieldsShort; |
| private int[] fieldsInteger; |
| private long[] fieldsLong; |
| |
| private float[] fieldsFloat; |
| private double[] fieldsDouble; |
| |
| private String[] fieldsString; |
| private Object[] fieldsObject; |
| |
| private transient FieldsDescriptor fieldDescriptor; |
| |
| /** |
| * Constructor for kryo serialization |
| */ |
| private GPOMutable() |
| { |
| //For kryo |
| } |
| |
| /** |
| * A copy constructor. |
| * @param gpo The {@link GPOMutable} object to copy. |
| */ |
| public GPOMutable(GPOMutable gpo) |
| { |
| this(gpo.getFieldDescriptor()); |
| |
| initialize(); |
| |
| //copying primitive values. |
| |
| { |
| boolean[] oldFieldsBoolean = gpo.getFieldsBoolean(); |
| if (oldFieldsBoolean != null) { |
| System.arraycopy(oldFieldsBoolean, 0, fieldsBoolean, 0, fieldsBoolean.length); |
| } |
| } |
| |
| { |
| char[] oldFieldsChar = gpo.getFieldsCharacter(); |
| if (oldFieldsChar != null) { |
| System.arraycopy(oldFieldsChar, 0, fieldsCharacter, 0, fieldsCharacter.length); |
| } |
| } |
| |
| { |
| byte[] oldFieldsByte = gpo.getFieldsByte(); |
| if (oldFieldsByte != null) { |
| System.arraycopy(oldFieldsByte, 0, fieldsByte, 0, fieldsByte.length); |
| } |
| } |
| |
| { |
| short[] oldFieldsShort = gpo.getFieldsShort(); |
| if (oldFieldsShort != null) { |
| System.arraycopy(oldFieldsShort, 0, fieldsShort, 0, fieldsShort.length); |
| } |
| } |
| |
| { |
| int[] oldFieldsInteger = gpo.getFieldsInteger(); |
| if (oldFieldsInteger != null) { |
| System.arraycopy(oldFieldsInteger, 0, fieldsInteger, 0, fieldsInteger.length); |
| } |
| } |
| |
| { |
| long[] oldFieldsLong = gpo.getFieldsLong(); |
| if (oldFieldsLong != null) { |
| System.arraycopy(oldFieldsLong, 0, fieldsLong, 0, fieldsLong.length); |
| } |
| } |
| |
| { |
| float[] oldFieldsFloat = gpo.getFieldsFloat(); |
| if (oldFieldsFloat != null) { |
| System.arraycopy(oldFieldsFloat, 0, fieldsFloat, 0, fieldsFloat.length); |
| } |
| } |
| |
| { |
| double[] oldFieldsDouble = gpo.getFieldsDouble(); |
| if (oldFieldsDouble != null) { |
| System.arraycopy(oldFieldsDouble, 0, fieldsDouble, 0, fieldsDouble.length); |
| } |
| } |
| |
| { |
| String[] oldFieldsString = gpo.getFieldsString(); |
| if (oldFieldsString != null) { |
| System.arraycopy(oldFieldsString, 0, fieldsString, 0, fieldsString.length); |
| } |
| } |
| |
| { |
| Object[] oldFieldsObject = gpo.getFieldsObject(); |
| if (oldFieldsObject != null) { |
| System.arraycopy(oldFieldsObject, 0, fieldsObject, 0, fieldsObject.length); |
| } |
| } |
| } |
| |
| /** |
| * This constructor copys the specified {@link Fields} from the specified {@link GPOMutable} object. |
| * @param gpo The {@link GPOMutable} object to copy fields from. |
| * @param subsetFields The fields to copy from the given GPOMutable object. |
| */ |
| public GPOMutable(GPOMutable gpo, Fields subsetFields) |
| { |
| this(gpo.getFieldDescriptor().getSubset(subsetFields)); |
| |
| initialize(); |
| |
| for (String field : this.getFieldDescriptor().getFields().getFields()) { |
| this.setFieldGeneric(field, gpo.getField(field)); |
| } |
| } |
| |
| /** |
| * This creates a GPOMutable object based off the given {@link FieldsDescriptor}. |
| * The values of the fields are initialized to their default primitive values. |
| * @param fieldDescriptor The {@link FieldsDescriptor} object describing the fields |
| * in this {@link GPOMutable} object. |
| */ |
| public GPOMutable(FieldsDescriptor fieldDescriptor) |
| { |
| setFieldDescriptor(fieldDescriptor); |
| |
| initialize(); |
| } |
| |
| /** |
| * Helper function to initialize the prinitive arrays in the {@link GPOMutable} object. |
| */ |
| private void initialize() |
| { |
| for (Type type : fieldDescriptor.getTypeToFields().keySet()) { |
| int size = fieldDescriptor.getTypeToSize().get(type); |
| switch (type) { |
| case BOOLEAN: { |
| fieldsBoolean = new boolean[size]; |
| break; |
| } |
| case CHAR: { |
| fieldsCharacter = new char[size]; |
| break; |
| } |
| case STRING: { |
| fieldsString = new String[size]; |
| break; |
| } |
| case BYTE: { |
| fieldsByte = new byte[size]; |
| break; |
| } |
| case SHORT: { |
| fieldsShort = new short[size]; |
| break; |
| } |
| case INTEGER: { |
| fieldsInteger = new int[size]; |
| break; |
| } |
| case LONG: { |
| fieldsLong = new long[size]; |
| break; |
| } |
| case FLOAT: { |
| fieldsFloat = new float[size]; |
| break; |
| } |
| case DOUBLE: { |
| fieldsDouble = new double[size]; |
| break; |
| } |
| case OBJECT: { |
| fieldsObject = new Object[size]; |
| break; |
| } |
| default: |
| throw new UnsupportedOperationException("The type " + type + " is not supported."); |
| } |
| } |
| } |
| |
| /** |
| * Gets the primitive array holding boolean fields. |
| * @return The primitive array holding boolean fields. |
| */ |
| public boolean[] getFieldsBoolean() |
| { |
| return fieldsBoolean; |
| } |
| |
| /** |
| * Gets the primitive array holding char fields. |
| * @return The primitive array holding char fields. |
| */ |
| public char[] getFieldsCharacter() |
| { |
| return fieldsCharacter; |
| } |
| |
| /** |
| * Gets the primitive array holding byte fields. |
| * @return The primitive array holding byte fields. |
| */ |
| public byte[] getFieldsByte() |
| { |
| return fieldsByte; |
| } |
| |
| /** |
| * Gets the primitive array holding short fields. |
| * @return The primitive array holding short fields. |
| */ |
| public short[] getFieldsShort() |
| { |
| return fieldsShort; |
| } |
| |
| /** |
| * Gets the primitive array holding integer fields. |
| * @return The primitive array holding integer fields. |
| */ |
| public int[] getFieldsInteger() |
| { |
| return fieldsInteger; |
| } |
| |
| /** |
| * Gets the primitive array holding long fields. |
| * @return The primitive array holding long fields. |
| */ |
| public long[] getFieldsLong() |
| { |
| return fieldsLong; |
| } |
| |
| /** |
| * Gets the primitive array holding float fields. |
| * @return The primitive array holding float fields. |
| */ |
| public float[] getFieldsFloat() |
| { |
| return fieldsFloat; |
| } |
| |
| /** |
| * Gets the primitive array holding double fields. |
| * @return The primitive array holding double fields. |
| */ |
| public double[] getFieldsDouble() |
| { |
| return fieldsDouble; |
| } |
| |
| /** |
| * Gets the primitive array holding string fields. |
| * @return The primitive array holding string fields. |
| */ |
| public String[] getFieldsString() |
| { |
| return fieldsString; |
| } |
| |
| /** |
| * Gets the array holding object fields. |
| * @return The array holding object fields. |
| */ |
| public Object[] getFieldsObject() |
| { |
| return fieldsObject; |
| } |
| |
| /** |
| * Sets the {@link FieldsDescriptor} on this {@link GPOMutable}. |
| * @param fieldDescriptor The {@link FieldsDescriptor} to set on this {@link GPOMutable}. |
| */ |
| public final void setFieldDescriptor(FieldsDescriptor fieldDescriptor) |
| { |
| this.fieldDescriptor = Preconditions.checkNotNull(fieldDescriptor); |
| } |
| |
| /** |
| * Gets the {@link FieldsDescriptor} on this {@link GPOMutable}. |
| * @return The {@link FieldsDescriptor} for this {@link GPOMutable}. |
| */ |
| public final FieldsDescriptor getFieldDescriptor() |
| { |
| return fieldDescriptor; |
| } |
| |
| /** |
| * Sets the specified field to the given value. |
| * @param field The name of the field to set. |
| * @param val The value to set the field to. |
| */ |
| public final void setFieldGeneric(String field, Object val) |
| { |
| Type type = fieldDescriptor.getType(field); |
| |
| if (type == null) { |
| throw new IllegalArgumentException(field + " is not a valid field of this object."); |
| } |
| |
| int index = fieldDescriptor.getTypeToFieldToIndex().get(type).get(field); |
| |
| switch (type) { |
| case BOOLEAN: { |
| fieldsBoolean[index] = (Boolean)val; |
| break; |
| } |
| case CHAR: { |
| fieldsCharacter[index] = (Character)val; |
| break; |
| } |
| case STRING: { |
| fieldsString[index] = (String)val; |
| break; |
| } |
| case BYTE: { |
| fieldsByte[index] = (Byte)val; |
| break; |
| } |
| case SHORT: { |
| fieldsShort[index] = (Short)val; |
| break; |
| } |
| case INTEGER: { |
| fieldsInteger[index] = (Integer)val; |
| break; |
| } |
| case LONG: { |
| fieldsLong[index] = (Long)val; |
| break; |
| } |
| case FLOAT: { |
| fieldsFloat[index] = (Float)val; |
| break; |
| } |
| case DOUBLE: { |
| fieldsDouble[index] = (Double)val; |
| break; |
| } |
| case OBJECT: { |
| fieldsObject[index] = val; |
| break; |
| } |
| default: |
| throw new UnsupportedOperationException("The type " + type + " is not supported."); |
| } |
| } |
| |
| /** |
| * Gets the value of the specified field. |
| * @param field The field whose value needs to be retrieved. |
| * @return The value of the specified field. |
| */ |
| public Object getField(String field) |
| { |
| Type type = fieldDescriptor.getType(field); |
| |
| if (type == null) { |
| throw new IllegalArgumentException(field + " is not a valid field of this object."); |
| } |
| |
| int index = fieldDescriptor.getTypeToFieldToIndex().get(type).get(field); |
| |
| switch (type) { |
| case BOOLEAN: { |
| return fieldsBoolean[index]; |
| } |
| case CHAR: { |
| return fieldsCharacter[index]; |
| } |
| case STRING: { |
| return fieldsString[index]; |
| } |
| case BYTE: { |
| return fieldsByte[index]; |
| } |
| case SHORT: { |
| return fieldsShort[index]; |
| } |
| case INTEGER: { |
| return fieldsInteger[index]; |
| } |
| case LONG: { |
| return fieldsLong[index]; |
| } |
| case FLOAT: { |
| return fieldsFloat[index]; |
| } |
| case DOUBLE: { |
| return fieldsDouble[index]; |
| } |
| default: |
| throw new UnsupportedOperationException("The type " + type + " is not supported."); |
| } |
| } |
| |
| /** |
| * Sets the given field to the given boolean value. |
| * @param field The field. |
| * @param val The value. |
| */ |
| public void setField(String field, boolean val) |
| { |
| throwInvalidField(field, Type.BOOLEAN); |
| fieldsBoolean[fieldDescriptor.getTypeToFieldToIndex().get(Type.BOOLEAN).get(field)] = val; |
| } |
| |
| /** |
| * Gets the boolean value of the given field. |
| * @param field The field. |
| * @return The value. |
| */ |
| public boolean getFieldBool(String field) |
| { |
| throwInvalidField(field, Type.BOOLEAN); |
| return fieldsBoolean[fieldDescriptor.getTypeToFieldToIndex().get(Type.BOOLEAN).get(field)]; |
| } |
| |
| /** |
| * Sets the given field to the given object value. |
| * @param field The field. |
| * @param val The value. |
| */ |
| public void setFieldObject(String field, Object val) |
| { |
| throwInvalidField(field, Type.OBJECT); |
| fieldsObject[fieldDescriptor.getTypeToFieldToIndex().get(Type.OBJECT).get(field)] = val; |
| } |
| |
| /** |
| * Gets the object value of the given field. |
| * @param field The field. |
| * @return The value. |
| */ |
| public Object getFieldObject(String field) |
| { |
| throwInvalidField(field, Type.OBJECT); |
| return fieldsObject[fieldDescriptor.getTypeToFieldToIndex().get(Type.OBJECT).get(field)]; |
| } |
| |
| /** |
| * Set the char value of the given field. |
| * @param field The field. |
| * @param val The value. |
| */ |
| public void setField(String field, char val) |
| { |
| throwInvalidField(field, Type.CHAR); |
| fieldsCharacter[fieldDescriptor.getTypeToFieldToIndex().get(Type.CHAR).get(field)] = val; |
| } |
| |
| /** |
| * Gets the char value of the given field. |
| * @param field The field. |
| * @return The value. |
| */ |
| public char getFieldChar(String field) |
| { |
| throwInvalidField(field, Type.CHAR); |
| return fieldsCharacter[fieldDescriptor.getTypeToFieldToIndex().get(Type.CHAR).get(field)]; |
| } |
| |
| /** |
| * Sets the byte value of the givne field. |
| * @param field The field. |
| * @param val The value. |
| */ |
| public void setField(String field, byte val) |
| { |
| throwInvalidField(field, Type.BYTE); |
| fieldsByte[fieldDescriptor.getTypeToFieldToIndex().get(Type.BYTE).get(field)] = val; |
| } |
| |
| /** |
| * Gets the byte value of the given field. |
| * @param field The field. |
| * @return The value. |
| */ |
| public byte getFieldByte(String field) |
| { |
| throwInvalidField(field, Type.BYTE); |
| return fieldsByte[fieldDescriptor.getTypeToFieldToIndex().get(Type.BYTE).get(field)]; |
| } |
| |
| /** |
| * Set the string value of the given field. |
| * @param field The field. |
| * @param val The value. |
| */ |
| public void setField(String field, String val) |
| { |
| throwInvalidField(field, Type.STRING); |
| fieldsString[fieldDescriptor.getTypeToFieldToIndex().get(Type.STRING).get(field)] = val; |
| } |
| |
| /** |
| * Gets the string value of the given field. |
| * @param field The field. |
| * @return The value. |
| */ |
| public String getFieldString(String field) |
| { |
| throwInvalidField(field, Type.STRING); |
| return fieldsString[fieldDescriptor.getTypeToFieldToIndex().get(Type.STRING).get(field)]; |
| } |
| |
| /** |
| * Sets the short value of the given field. |
| * @param field The field. |
| * @param val The value. |
| */ |
| public void setField(String field, short val) |
| { |
| throwInvalidField(field, Type.SHORT); |
| fieldsShort[fieldDescriptor.getTypeToFieldToIndex().get(Type.SHORT).get(field)] = val; |
| } |
| |
| /** |
| * Gets the short value of the given field. |
| * @param field The field. |
| * @return The value. |
| */ |
| public short getFieldShort(String field) |
| { |
| throwInvalidField(field, Type.SHORT); |
| return fieldsShort[fieldDescriptor.getTypeToFieldToIndex().get(Type.SHORT).get(field)]; |
| } |
| |
| /** |
| * Sets the int value of the given field. |
| * @param field The field. |
| * @param val The value. |
| */ |
| public void setField(String field, int val) |
| { |
| throwInvalidField(field, Type.INTEGER); |
| fieldsInteger[fieldDescriptor.getTypeToFieldToIndex().get(Type.INTEGER).get(field)] = val; |
| } |
| |
| /** |
| * Gets the int value of the given field. |
| * @param field The field. |
| * @return The value. |
| */ |
| public int getFieldInt(String field) |
| { |
| throwInvalidField(field, Type.INTEGER); |
| return fieldsInteger[fieldDescriptor.getTypeToFieldToIndex().get(Type.INTEGER).get(field)]; |
| } |
| |
| /** |
| * Sets the long value of the given field. |
| * @param field The field. |
| * @param val The value. |
| */ |
| public void setField(String field, long val) |
| { |
| throwInvalidField(field, Type.LONG); |
| fieldsLong[fieldDescriptor.getTypeToFieldToIndex().get(Type.LONG).get(field)] = val; |
| } |
| |
| /** |
| * Gets the long value of the given field. |
| * @param field The field. |
| * @return The value. |
| */ |
| public long getFieldLong(String field) |
| { |
| throwInvalidField(field, Type.LONG); |
| return fieldsLong[fieldDescriptor.getTypeToFieldToIndex().get(Type.LONG).get(field)]; |
| } |
| |
| /** |
| * Sets the float value of the given field. |
| * @param field The field. |
| * @param val The float value. |
| */ |
| public void setField(String field, float val) |
| { |
| throwInvalidField(field, Type.FLOAT); |
| fieldsFloat[fieldDescriptor.getTypeToFieldToIndex().get(Type.FLOAT).get(field)] = val; |
| } |
| |
| /** |
| * Gets the float value of the given field. |
| * @param field The field. |
| * @return The value. |
| */ |
| public float getFieldFloat(String field) |
| { |
| throwInvalidField(field, Type.FLOAT); |
| return fieldsFloat[fieldDescriptor.getTypeToFieldToIndex().get(Type.FLOAT).get(field)]; |
| } |
| |
| /** |
| * Sets the double value of the given field. |
| * @param field The field. |
| * @param val The value. |
| */ |
| public void setField(String field, double val) |
| { |
| throwInvalidField(field, Type.DOUBLE); |
| fieldsDouble[fieldDescriptor.getTypeToFieldToIndex().get(Type.DOUBLE).get(field)] = val; |
| } |
| |
| /** |
| * Gets the double value of the given field. |
| * @param field The field. |
| * @return The value. |
| */ |
| public double getFieldDouble(String field) |
| { |
| throwInvalidField(field, Type.DOUBLE); |
| return fieldsDouble[fieldDescriptor.getTypeToFieldToIndex().get(Type.DOUBLE).get(field)]; |
| } |
| |
| /** |
| * This is a helper method which throws an exception if the given field of the |
| * given type doesn't exist for this {@link GPOMutable} object. |
| * @param field The name of the field. |
| * @param type The type of the field. |
| */ |
| private void throwInvalidField(String field, Type type) |
| { |
| Type fieldType = fieldDescriptor.getType(field); |
| if (fieldType == null || !fieldType.equals(type)) { |
| throw new IllegalArgumentException(field + " is not a valid field of type " + type + " on this object."); |
| } |
| } |
| |
| public void applyObjectPayloadFix() |
| { |
| if (fieldDescriptor.getSerdePayloadFix() != null) { |
| fieldDescriptor.getSerdePayloadFix().fix(fieldsObject); |
| } |
| } |
| |
| @Override |
| public int hashCode() |
| { |
| int hash = 7; |
| hash = 23 * hash + Arrays.hashCode(this.fieldsBoolean); |
| hash = 23 * hash + Arrays.hashCode(this.fieldsCharacter); |
| hash = 23 * hash + Arrays.hashCode(this.fieldsByte); |
| hash = 23 * hash + Arrays.hashCode(this.fieldsShort); |
| hash = 23 * hash + Arrays.hashCode(this.fieldsInteger); |
| hash = 23 * hash + Arrays.hashCode(this.fieldsLong); |
| hash = 23 * hash + Arrays.hashCode(this.fieldsFloat); |
| hash = 23 * hash + Arrays.hashCode(this.fieldsDouble); |
| hash = 23 * hash + Arrays.deepHashCode(this.fieldsString); |
| hash = 23 * hash + (this.fieldDescriptor != null ? this.fieldDescriptor.hashCode() : 0); |
| return hash; |
| } |
| |
| @Override |
| public boolean equals(Object obj) |
| { |
| if (obj == null) { |
| return false; |
| } |
| if (!(obj instanceof GPOMutable)) { |
| return false; |
| } |
| final GPOMutable other = (GPOMutable)obj; |
| if (!Arrays.equals(this.fieldsBoolean, other.fieldsBoolean)) { |
| return false; |
| } |
| if (!Arrays.equals(this.fieldsCharacter, other.fieldsCharacter)) { |
| return false; |
| } |
| if (!Arrays.equals(this.fieldsByte, other.fieldsByte)) { |
| return false; |
| } |
| if (!Arrays.equals(this.fieldsShort, other.fieldsShort)) { |
| return false; |
| } |
| if (!Arrays.equals(this.fieldsInteger, other.fieldsInteger)) { |
| return false; |
| } |
| if (!Arrays.equals(this.fieldsLong, other.fieldsLong)) { |
| return false; |
| } |
| if (!Arrays.equals(this.fieldsFloat, other.fieldsFloat)) { |
| return false; |
| } |
| if (!Arrays.equals(this.fieldsDouble, other.fieldsDouble)) { |
| return false; |
| } |
| if (!Arrays.deepEquals(this.fieldsString, other.fieldsString)) { |
| return false; |
| } |
| if (!Arrays.deepEquals(this.fieldsObject, other.fieldsObject)) { |
| return false; |
| } |
| if (this.fieldDescriptor != other.fieldDescriptor && (this.fieldDescriptor == null |
| || !this.fieldDescriptor.equals(other.fieldDescriptor))) { |
| return false; |
| } |
| return true; |
| } |
| |
| @Override |
| public String toString() |
| { |
| return "GPOMutable{" + "fieldsBoolean=" + Arrays.toString(fieldsBoolean) + ", fieldsCharacter=" |
| + Arrays.toString(fieldsCharacter) + ", fieldsByte=" + Arrays.toString(fieldsByte) + ", fieldsShort=" |
| + Arrays.toString(fieldsShort) + ", fieldsInteger=" + Arrays.toString(fieldsInteger) + ", fieldsLong=" |
| + Arrays.toString(fieldsLong) + ", fieldsFloat=" + Arrays.toString(fieldsFloat) + ", fieldsDouble=" |
| + Arrays.toString(fieldsDouble) + ", fieldsString=" + Arrays.toString(fieldsString) + ", fieldDescriptor=" |
| + fieldDescriptor + '}'; |
| } |
| } |