blob: 4e9307ae8aa75883bd4c14d34f536cc7e4ad9013 [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.Iterator;
import java.util.List;
import java.util.Vector;
import org.eclipse.persistence.internal.eis.cobol.helper.ByteConverter;
import org.eclipse.persistence.internal.eis.cobol.helper.Helper;
import org.eclipse.persistence.internal.helper.DatabaseField;
/**
* <b>Purpose</b>: This class defines the <code>FieldMetaData</code> interface it defines
* various behavior associated with a field and stores meta-information about the field.
* <code>ElementaryFieldMetaData</code> represents a field that contains a direct value and
* no subordinate fields, a root in the hierarchy.
*/
public class ElementaryFieldMetaData implements FieldMetaData {
/** This is the record that contains this field */
protected RecordMetaData myRecord;
/** This is the name of the field */
protected String myName;
/** This is the size of the field */
protected int mySize;
/** This is the offset of the field within the record byte array */
protected int myOffset;
/** This is the type of data the field contains */
protected int myType;
/** This is true if this field is redefined */
protected boolean isRedefine;
/** This is the offset of the decimal position within the digits of a numeric field */
protected int decimalPosition;
/** This is the field that this field redefines */
protected FieldMetaData myFieldRedefined;
/** This is the number of elements in the array if this field is an array type */
protected int myArraySize;
/** This is populated if the arraySize is dependent on another field */
protected String myDependentFieldName;
/** This is true if the field is a numeric field that is signed */
protected boolean isSigned;
public ElementaryFieldMetaData() {
initialize();
}
public ElementaryFieldMetaData(String fieldName, String recordName) {
initialize(fieldName, recordName);
}
public ElementaryFieldMetaData(String fieldName, RecordMetaData record) {
initialize(fieldName, record);
}
protected void initialize() {
myRecord = new RecordMetaData();
isRedefine = false;
decimalPosition = -1;
myArraySize = -1;
isSigned = false;
myDependentFieldName = "";
}
protected void initialize(String fieldName, String recordName) {
myName = fieldName;
myRecord = new RecordMetaData(recordName);
isRedefine = false;
decimalPosition = -1;
myArraySize = -1;
isSigned = false;
myDependentFieldName = "";
}
protected void initialize(String fieldName, RecordMetaData record) {
myName = fieldName;
myRecord = record;
isRedefine = false;
decimalPosition = -1;
myArraySize = -1;
isSigned = false;
myDependentFieldName = "";
}
/**
* performs a deep copy of all the attributes of the field
*/
@Override
public FieldMetaData deepCopy() {
FieldMetaData fieldCopy = new ElementaryFieldMetaData(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);
fieldCopy.setIsSigned(isSigned);
return fieldCopy;
}
/**
* returns true if field is a signed numeric field
*/
@Override
public boolean isSigned() {
return isSigned;
}
/**
* setter for isSigned
*/
@Override
public void setIsSigned(boolean signed) {
isSigned = signed;
}
/**
* returns true if the field is a numeric field with a decimal marker
*/
@Override
public boolean hasDecimal() {
if (decimalPosition == -1) {
return false;
} else {
return true;
}
}
/**
* getter for decimalPosition
*/
@Override
public int getDecimalPosition() {
return decimalPosition;
}
/**
* setter for decimalPosition
*/
@Override
public void setDecimalPosition(int newPosition) {
decimalPosition = newPosition;
}
/**
* getter for myName
*/
@Override
public String getName() {
return myName;
}
/**
* setter for myName
*/
@Override
public void setName(String newName) {
myName = newName;
}
/**
* getter for myRecord
*/
@Override
public RecordMetaData getRecord() {
return myRecord;
}
/**
* setter for myRecord
*/
@Override
public void setRecord(RecordMetaData newRecord) {
myRecord = newRecord;
}
/**
* getter for mySize, multiplies field size my array size if field is an array to get
* total size
*/
@Override
public int getSize() {
/*if(this.isArray())
return mySize * myArraySize;
else*/
return mySize;
}
/**
* setter for mySize
*/
@Override
public void setSize(int size) {
mySize = size;
}
/**
* returns true if field is composite, since this is elementary, it always returns false
*/
@Override
public boolean isComposite() {
return false;
}
/**
* returns an empty vector since an elementary field should have no subordinate fields
*/
public Vector getCompositeFields() {
return new Vector();
}
/**
* getter for myOffset
*/
@Override
public int getOffset() {
return myOffset;
}
/**
* setter for myOffset
*/
@Override
public void setOffset(int offset) {
myOffset = offset;
}
/**
* getter for myType
*/
@Override
public int getType() {
return myType;
}
/**
* setter for myType
*/
@Override
public void setType(int type) {
myType = type;
}
/**
* returns true if field is a redefine
*/
@Override
public boolean isFieldRedefine() {
return isRedefine;
}
/**
* setter for isRedefine
*/
@Override
public void setIsFieldRedefine(boolean status) {
isRedefine = status;
}
/**
* setter for myFieldRedefined
*/
@Override
public void setFieldRedefined(FieldMetaData field) {
myFieldRedefined = field;
if (field != null) {
isRedefine = true;
} else {
isRedefine = false;
}
}
/**
* getter for myFieldRedefined
*/
@Override
public FieldMetaData getFieldRedefined() {
return myFieldRedefined;
}
/**
* returns true if field is an array
*/
@Override
public boolean isArray() {
return (myArraySize > 0);
}
/**
* getter for array size
*/
@Override
public int getArraySize() {
return myArraySize;
}
/**
* setter for myArraySize
*/
@Override
public void setArraySize(int newSize) {
myArraySize = newSize;
}
/**
* returns true if this field has a dependent field
*/
@Override
public boolean dependsOn() {
return (!myDependentFieldName.isEmpty());
}
/**
* getter for myDependentFieldName
*/
@Override
public String getDependentFieldName() {
return myDependentFieldName;
}
/**
* setter for myDependentFieldName
*/
@Override
public void setDependentFieldName(String fieldName) {
myDependentFieldName = fieldName;
}
/**
* this method extracts and returns the value for the field, if the field is an
* array, the value is an <code>Vector</code>
*/
@Override
public Object extractValueFromArray(byte[] recordData) {
Object value;
if (this.isArray()) {
int offset = this.getOffset();
List<String> fieldValue = new ArrayList<>(this.getArraySize());
for (int i = this.getArraySize(); i > 0; i--) {
FieldMetaData fieldCopy = this.deepCopy();
fieldCopy.setOffset(offset);
ByteConverter converter = new ByteConverter(fieldCopy, recordData);
fieldValue.add(converter.getStringValue());
offset += mySize;
}
value = fieldValue;
} else {
ByteConverter converter = new ByteConverter(this, recordData);
value = converter.getStringValue();
}
return value;
}
/**
* this method adjusts the array size to the value in its dependent field
*/
protected void adjustArraySize(CobolRow row) {
Integer intValue = Helper.integerFromString(row.get(this.getDependentFieldName()).toString());
if (intValue != null) {
this.setArraySize(intValue);
}
}
/**
* this method will write its value to the row provided
*/
@Override
public void writeOnRow(CobolRow row, byte[] recordData) {
DatabaseField field = new DatabaseField(this.getName(), this.getRecord().getName());
Object value;
//check for array first adjust size if necessary
if (this.isArray() && this.dependsOn()) {
adjustArraySize(row);
}
if (!this.isFieldRedefine()) {
value = extractValueFromArray(recordData);
}
//redefined field handle accordingly
else {
value = new CobolRedefinedFieldValue(this, recordData);
}
row.add(field, value);
}
/**
* this method will write its value from the row to the record data byte array
*/
@Override
public void writeOnArray(CobolRow row, byte[] recordData) {
Object value = row.get(this.getName());
ByteConverter converter;
if (this.isArray()) {
//check for array first adjust size if necessary
if (this.dependsOn()) {
adjustArraySize(row);
}
int offset = this.getOffset();
@SuppressWarnings({"unchecked"})
Iterator<String> elements = ((List<String>)value).iterator();
for (int i = this.getArraySize(); i > 0; i--) {
FieldMetaData fieldCopy = this.deepCopy();
fieldCopy.setOffset(offset);
converter = new ByteConverter(fieldCopy, recordData);
String elementValue = elements.next();
converter.setBytesToValue(elementValue);
offset += mySize;
}
} else {
converter = new ByteConverter(this, recordData);
converter.setBytesToValue((String)value);
}
}
}