blob: 8ff4f3c1ffe7fe453c20e14389db6f48ce73d0ec [file] [log] [blame]
/*
* Copyright (c) 1998, 2021 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 v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// Oracle - initial API and implementation from Oracle TopLink
package org.eclipse.persistence.internal.eis.cobol;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import org.eclipse.persistence.internal.helper.DatabaseField;
/**
* <b>Purpose</b>: This class represents metadata for composite fields. It exetends
* <code>ElementaryFieldMetaData</code> and adds teh attribute <code>myCompositeFields</code>
* which is a collection of subordinate fields.
*/
public class CompositeFieldMetaData extends ElementaryFieldMetaData implements CompositeObject {
/** collection containing this fields subordinate fields */
protected Vector<FieldMetaData> myCompositeFields;
public CompositeFieldMetaData() {
super.initialize();
initialize();
}
public CompositeFieldMetaData(String fieldName, String recordName) {
super.initialize(fieldName, recordName);
initialize();
}
public CompositeFieldMetaData(String fieldName, RecordMetaData record) {
super.initialize(fieldName, record);
initialize();
}
public CompositeFieldMetaData(String fieldName, RecordMetaData record, Vector<FieldMetaData> fields) {
super.initialize(fieldName, record);
initialize(fields);
}
@Override
protected void initialize() {
myCompositeFields = new Vector<>();
}
protected void initialize(Vector<FieldMetaData> fields) {
myCompositeFields = fields;
}
/**
* performs a deep copy of all subordiate fields in the <code>myCompositeFields</code> attribute
*/
@Override
public FieldMetaData deepCopy() {
CompositeFieldMetaData fieldCopy = new CompositeFieldMetaData(myName, myRecord.getName());
fieldCopy.setIsFieldRedefine(isRedefine);
fieldCopy.setDecimalPosition(decimalPosition);
fieldCopy.setArraySize(myArraySize);
fieldCopy.setSize(mySize);
fieldCopy.setOffset(myOffset);
fieldCopy.setType(myType);
if (isFieldRedefine()) {
fieldCopy.setFieldRedefined(myFieldRedefined.deepCopy());
}
fieldCopy.setDependentFieldName(myDependentFieldName);
Enumeration<FieldMetaData> fieldsEnum = myCompositeFields.elements();
while (fieldsEnum.hasMoreElements()) {
FieldMetaData field = fieldsEnum.nextElement();
fieldCopy.addField(field.deepCopy());
}
return fieldCopy;
}
/**
* overides <code>ElementaryFieldMetaData</code> to calculate the fields size from all the sizes
* of its subordinate fields.
*/
@Override
public int getSize() {
Enumeration<FieldMetaData> fieldsEnum = myCompositeFields.elements();
int size = 0;
while (fieldsEnum.hasMoreElements()) {
FieldMetaData field = fieldsEnum.nextElement();
if (!field.isFieldRedefine()) {
size += field.getSize();
}
}
/*if(isArray())
return size * myArraySize;
else*/
return size;
}
/**
* we don't want to set the size for a composite field because its size is determined from its
* subordinate fields.
*/
@Override
public void setSize(int size) {
//do nothing
}
/**
* a composite field can't have a decimal position
*/
@Override
public boolean hasDecimal() {
return false;
}
/**
* a composite field can't have a decimal position
*/
@Override
public int getDecimalPosition() {
return -1;
}
/**
* a composite field can't have a decimal position
*/
public void setDecimalPosition() {
//do nothing
}
/**
* a composite field is by definition going to be composite
*/
@Override
public boolean isComposite() {
return true;
}
/**
* a composite field is by definition going to be composite
*/
@Override
public int getType() {
return FieldMetaData.COMPOSITE;
}
/**
* a composite field is by definition going to be composite, so this cannot be changed
*/
@Override
public void setType(int type) {
//do nothing
}
/**
* returns a collection of subordinate fields
*/
@Override
public Vector<FieldMetaData> getFields() {
return myCompositeFields;
}
/**
* sets the composite field attribute to the new collection
*/
@Override
public void setFields(Vector<FieldMetaData> newCompositeFields) {
myCompositeFields = newCompositeFields;
}
/**
* adds a field to the collection
*/
@Override
public void addField(FieldMetaData newField) {
myCompositeFields.addElement(newField);
}
/**
* returns the first subordinate field with a name matching the string in <code>fieldName</code>
*/
@Override
public FieldMetaData getFieldNamed(String fieldName) {
Enumeration<FieldMetaData> fieldsEnum = getFields().elements();
while (fieldsEnum.hasMoreElements()) {
FieldMetaData field = fieldsEnum.nextElement();
if (field.getName().equals(fieldName)) {
return field;
}
}
return null;
}
/**
* loops through the subordinate fields extracting the value from each.
*/
@Override
public Object extractValueFromArray(byte[] recordData) {
List<CobolRow> fieldValue = new ArrayList<>(getFields().size());
if (this.isArray()) {
int offset = this.getOffset();
for (int i = this.getArraySize(); i > 0; i--) {
//must change offset to read the appropriate section of the byte array
CompositeFieldMetaData fieldCopy = (CompositeFieldMetaData)this.deepCopy();
fieldCopy.setOffset(offset);
fieldCopy.resetChildOffsets();
CobolRow compositeRow = new CobolRow();
fieldCopy.writeCompositeOnRow(compositeRow, recordData);
fieldValue.add(compositeRow);
offset += this.getSize();
}
} else {
CobolRow compositeRow = new CobolRow();
writeCompositeOnRow(compositeRow, recordData);
fieldValue.add(compositeRow);
}
return fieldValue;
}
/**
* writes individual fields on given row
*/
public void writeCompositeOnRow(CobolRow row, byte[] recordData) {
Enumeration<FieldMetaData> fields = getFields().elements();
while (fields.hasMoreElements()) {
FieldMetaData currentField = fields.nextElement();
currentField.writeOnRow(row, recordData);
}
}
/**
* extracts the value from the record data for the field and writes it to the row.
*/
@Override
public void writeOnRow(CobolRow row, byte[] recordData) {
Object value;
//check for array first adjust size if necessary
if (this.isArray() && this.dependsOn()) {
adjustArraySize(row);
}
DatabaseField field = new DatabaseField(getName(), getRecord().getName());
if (this.isFieldRedefine()) {
value = new CobolRedefinedFieldValue(this, recordData);
} else {
value = extractValueFromArray(recordData);
}
row.add(field, value);
}
/**
* takes the value from the row for this field and writes it to the byte array
*/
@Override
public void writeOnArray(CobolRow row, byte[] recordData) {
Object obj = row.get(this.getName());
@SuppressWarnings({"unchecked"})
List<CobolRow> fieldValue = (List<CobolRow>)obj;
if (this.isArray()) {
//check for array first adjust size if necessary
if (this.dependsOn()) {
adjustArraySize(row);
}
int offset = this.getOffset();
Iterator<CobolRow> elements = fieldValue.iterator();
for (int i = this.getArraySize(); i > 0; i--) {
//must change offset to write to the appropriate section of the byte array
CompositeFieldMetaData fieldCopy = (CompositeFieldMetaData)this.deepCopy();
fieldCopy.setOffset(offset);
fieldCopy.resetChildOffsets();
CobolRow compositeRow = elements.next();
fieldCopy.writeCompositeOnArray(compositeRow, recordData);
offset += this.getSize();
}
} else {
CobolRow compositeRow = fieldValue.get(0);
this.writeCompositeOnArray(compositeRow, recordData);
}
}
/**
* This method is used by fields that are array values to write themselves to arrays
*/
protected void writeCompositeOnArray(CobolRow row, byte[] recordData) {
Enumeration<FieldMetaData> fields = getFields().elements();
while (fields.hasMoreElements()) {
FieldMetaData currentField = fields.nextElement();
currentField.writeOnArray(row, recordData);
}
}
/**
* method resets offsets of subordinate fields, should be called when the offset of the parent
* is changed.
*/
protected void resetChildOffsets() {
Enumeration<FieldMetaData> childFieldsEnum = myCompositeFields.elements();
int offset = this.getOffset();
while (childFieldsEnum.hasMoreElements()) {
FieldMetaData field = childFieldsEnum.nextElement();
field.setOffset(offset);
if (field.isComposite()) {
((CompositeFieldMetaData)field).resetChildOffsets();
}
offset += field.getSize();
}
}
}