/******************************************************************************* * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 * which accompanies this distribution. * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * Oracle - initial API and implementation from Oracle TopLink ******************************************************************************/ package org.eclipse.persistence.internal.sessions; import java.io.StringWriter; import java.util.*; import org.eclipse.persistence.internal.helper.*; import org.eclipse.persistence.sessions.DatabaseRecord; import org.eclipse.persistence.internal.helper.DatabaseField; /** * PERF: Optimized record implementation using arrays instead of Vector. * Currently only used when fetch rows from the database. */ public class ArrayRecord extends DatabaseRecord { protected DatabaseField[] fieldsArray; protected Object[] valuesArray; protected ArrayRecord() { super(); } public ArrayRecord(Vector fields, DatabaseField[] fieldsArray, Object[] valuesArray) { super(fields, null, fieldsArray.length); this.fieldsArray = fieldsArray; this.valuesArray = valuesArray; } /** * Reset the fields and values from the arrays. * This removes the optimization if a non-optimized method is called. */ protected void checkValues() { if (this.values == null) { this.values = new NonSynchronizedVector(this.valuesArray.length); for (Object value : this.valuesArray) { this.values.add(value); } } } /** * INTERNAL: * Add the field-value pair to the row. Will not check, * will simply add to the end of the row */ public void add(DatabaseField key, Object value) { checkValues(); this.fieldsArray = null; this.valuesArray = null; super.add(key, value); } /** * PUBLIC: * Clear the contents of the row. */ public void clear() { this.fieldsArray = null; this.valuesArray = null; super.clear(); } /** * INTERNAL: * Clone the row and its values. */ public AbstractRecord clone() { checkValues(); return super.clone(); } /** * INTERNAL: * Check if the field is contained in the row. */ public boolean containsKey(DatabaseField key) { if (this.fieldsArray != null) { // Optimize check. int index = key.index; if ((index >= 0) && (index < this.size)) { DatabaseField field = this.fieldsArray[index]; if ((field == key) || field.equals(key)) { return true; } } for (DatabaseField field : this.fieldsArray) { if ((field == key) || field.equals(key)) { return true; } } return false; } else { return super.containsKey(key); } } /** * PUBLIC: * Check if the value is contained in the row. */ public boolean containsValue(Object value) { if (this.valuesArray != null) { for (Object rowValue : this.valuesArray) { if ((value == rowValue) || rowValue.equals(value)) { return true; } } return false; } else { return super.containsValue(value); } } /** * INTERNAL: * Retrieve the value for the field. If missing null is returned. */ public Object get(DatabaseField key) { if (this.fieldsArray != null) { // Optimize check. int index = key.index; if ((index >= 0) && (index < this.size)) { DatabaseField field = this.fieldsArray[index]; if ((field == key) || field.equals(key)) { return this.valuesArray[index]; } } for (int fieldIndex = 0; fieldIndex < this.size; fieldIndex++) { DatabaseField field = this.fieldsArray[fieldIndex]; if ((field == key) || field.equals(key)) { // PERF: If the fields index was not set, then set it. if (index == -1) { key.setIndex(fieldIndex); } return this.valuesArray[fieldIndex]; } } return null; } else { return super.get(key); } } /** * INTERNAL: * Retrieve the value for the field. If missing DatabaseRow.noEntry is returned. */ public Object getIndicatingNoEntry(DatabaseField key) { if (this.fieldsArray != null) { // Optimize check. int index = key.index; if ((index >= 0) && (index < this.size)) { DatabaseField field = this.fieldsArray[index]; if ((field == key) || field.equals(key)) { return this.valuesArray[index]; } } for (int fieldIndex = 0; fieldIndex < this.size; fieldIndex++) { DatabaseField field = this.fieldsArray[fieldIndex]; if ((field == key) || field.equals(key)) { // PERF: If the fields index was not set, then set it. if (index == -1) { key.setIndex(fieldIndex); } return this.valuesArray[fieldIndex]; } } return AbstractRecord.noEntry; } else { return super.get(key); } } /** * INTERNAL: * Returns the row's field with the same name. */ public DatabaseField getField(DatabaseField key) { if (this.fieldsArray != null) { // Optimize check. int index = key.index; if ((index >= 0) && (index < this.size)) { DatabaseField field = this.fieldsArray[index]; if ((field == key) || field.equals(key)) { return field; } } for (int fieldIndex = 0; fieldIndex < this.size; fieldIndex++) { DatabaseField field = this.fieldsArray[fieldIndex]; if ((field == key) || field.equals(key)) { return field; } } return null; } else { return super.getField(key); } } /** * INTERNAL: */ public Vector getFields() { checkValues(); return super.getFields(); } /** * INTERNAL: */ public Vector getValues() { checkValues(); return super.getValues(); } /** * INTERNAL: * Add the field-value pair to the row. */ public Object put(DatabaseField key, Object value) { checkValues(); this.fieldsArray = null; this.valuesArray = null; return super.put(key, value); } /** * INTERNAL: * Remove the field key from the row. */ public Object remove(DatabaseField key) { checkValues(); this.fieldsArray = null; this.valuesArray = null; return super.remove(key); } /** * INTERNAL: * replaces the value at index with value */ public void replaceAt(Object value, int index) { if (this.valuesArray != null) { this.valuesArray[index] = value; } else { super.replaceAt(value, index); } } /** * INTERNAL: * replaces the value at field with value */ public void replaceAt(Object value, DatabaseField key) { if (this.fieldsArray != null) { // Optimize check. int index = key.index; if ((index >= 0) && (index < this.size)) { DatabaseField field = this.fieldsArray[index]; if ((field == key) || field.equals(key)) { this.valuesArray[index] = value; return; } } for (int fieldIndex = 0; fieldIndex < this.size; fieldIndex++) { DatabaseField field = this.fieldsArray[fieldIndex]; if ((field == key) || field.equals(key)) { // PERF: If the fields index was not set, then set it. if (index == -1) { key.setIndex(fieldIndex); } this.valuesArray[fieldIndex] = value; return; } } } else { super.replaceAt(value, key); } } protected void setFields(Vector fields) { checkValues(); this.fieldsArray = null; this.valuesArray = null; super.setFields(fields); } protected void setValues(Vector values) { checkValues(); this.fieldsArray = null; this.valuesArray = null; super.setValues(values); } /** * PUBLIC: * Return the number of field/value pairs in the row. */ public int size() { if (this.fieldsArray == null) { return this.fields.size(); } else { return this.fieldsArray.length; } } @Override public String toString() { if (this.valuesArray != null) { StringWriter writer = new StringWriter(); writer.write(Helper.getShortClassName(getClass())); writer.write("("); writer.write(toStringAditional()); for (int index = 0; index < this.fieldsArray.length; index++) { writer.write(Helper.cr()); writer.write("\t"); writer.write(String.valueOf(this.fieldsArray[index])); writer.write(" => "); writer.write(String.valueOf(this.valuesArray[index])); } if (this.sopObject != null) { writer.write(Helper.cr()); writer.write(" sopObject = "); writer.write(this.sopObject.toString()); } writer.write(")"); return writer.toString(); } else { return super.toString(); } } protected String toStringAditional() { return ""; } }