| /* |
| * Copyright (c) 1998, 2020 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 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 fields) { |
| super.initialize(fieldName, record); |
| initialize(fields); |
| } |
| |
| @Override |
| protected void initialize() { |
| myCompositeFields = new Vector(); |
| } |
| |
| protected void initialize(Vector 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 fieldsEnum = myCompositeFields.elements(); |
| while (fieldsEnum.hasMoreElements()) { |
| FieldMetaData field = (FieldMetaData)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 fieldsEnum = myCompositeFields.elements(); |
| int size = 0; |
| while (fieldsEnum.hasMoreElements()) { |
| FieldMetaData field = (FieldMetaData)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 getFields() { |
| return myCompositeFields; |
| } |
| |
| /** |
| * sets the composite field attribute to the new collection |
| */ |
| @Override |
| public void setFields(Vector 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 fieldsEnum = getFields().elements(); |
| while (fieldsEnum.hasMoreElements()) { |
| FieldMetaData field = (FieldMetaData)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) { |
| ArrayList 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 fields = getFields().elements(); |
| while (fields.hasMoreElements()) { |
| FieldMetaData currentField = (FieldMetaData)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()); |
| List fieldValue = (List)obj; |
| if (this.isArray()) { |
| //check for array first adjust size if necessary |
| if (this.dependsOn()) { |
| adjustArraySize(row); |
| } |
| int offset = this.getOffset(); |
| Iterator 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 = (CobolRow)elements.next(); |
| fieldCopy.writeCompositeOnArray(compositeRow, recordData); |
| offset += this.getSize(); |
| } |
| } else { |
| CobolRow compositeRow = (CobolRow)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 fields = getFields().elements(); |
| while (fields.hasMoreElements()) { |
| FieldMetaData currentField = (FieldMetaData)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 childFieldsEnum = myCompositeFields.elements(); |
| int offset = this.getOffset(); |
| while (childFieldsEnum.hasMoreElements()) { |
| FieldMetaData field = (FieldMetaData)childFieldsEnum.nextElement(); |
| field.setOffset(offset); |
| if (field.isComposite()) { |
| ((CompositeFieldMetaData)field).resetChildOffsets(); |
| } |
| offset += field.getSize(); |
| } |
| } |
| } |