src.com.ibm.as400.access.Record Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jt400-jdk8 Show documentation
Show all versions of jt400-jdk8 Show documentation
The Open Source version of the IBM Toolbox for Java
The newest version!
///////////////////////////////////////////////////////////////////////////////
//
// JTOpen (IBM Toolbox for Java - OSS version)
//
// Filename: Record.java
//
// The source code contained herein is licensed under the IBM Public License
// Version 1.0, which has been approved by the Open Source Initiative.
// Copyright (C) 1997-2004 International Business Machines Corporation and
// others. All rights reserved.
//
///////////////////////////////////////////////////////////////////////////////
// @A2 11/21/2007 - Change to setField() method to calculation of the value for
// variableFieldLength. Shift-in/shift-out characters need to
// be included for some CCSIDs.
// Similar change in getField for VARGRAPHIC fields. The 2-byte
// length field (which preceeds the field data) indicates the
// number of "graphic characters" (NOT the number of "bytes").
// Each graphic character is 2-bytes each. Therefore, the code
// must multiply the length by 2 to read the correct number of
// bytes.
// This is opposite from a VARCHAR field... where the 2-byte
// length field (which preceeds the field data) indicates the
// number of "bytes" of character data (NOT the number of
// characters). This is because some characters may be represented
// by a single byte or more than a single byte.
// Fix for CPS DB Item: 795LZ6 - DBCS issue with VARCHAR on JTOpen Record Level Access
///////////////////////////////////////////////////////////////////////////////
package com.ibm.as400.access;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.CharConversionException;
import java.io.UnsupportedEncodingException;
import java.io.Serializable;
import java.beans.PropertyChangeSupport;
import java.beans.VetoableChangeSupport;
import java.beans.PropertyChangeListener;
import java.beans.VetoableChangeListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyVetoException;
import java.util.Vector;
/**
*The Record class represents the data described by a RecordFormat object.
*It can represent:
*
*- An entry in a data queue.
*
- The parameter data provided to or returned by a program call.
*
- A record to be written to or read from a file on the system.
*
- Any data returned from the system that needs to be converted
*between IBM i format and Java format.
*
*Record objects generate the following events:
*
*- {@link com.ibm.as400.access.RecordDescriptionEvent RecordDescriptionEvent}
*
The events fired are:
*
*- fieldModified()
*
* - PropertyChangeEvent
*
- VetoableChangeEvent
*
*Examples
*
*- Using the Record class with the Data queue classes
*
- Using the Record class with the record-level database access classes
*
**/
public class Record implements Serializable
{
static final long serialVersionUID = 4L;
// The server data for this record.
private byte[] as400Data_;
// Array of the field descriptions that describe the fields in this record.
// We initialize from RecordFormat.getFieldDescriptions() during construction
// or setRecordFormat().
private FieldDescription[] fieldDescriptions_;
// Array of the fields that make up this record.
private Object[] fields_;
// Array containing the offset in as400Data_ for each field.
// These values are only guaranteed to be valid if the record
// does not contain dependent fields.
private int[] fieldOffsets_;
// Indicates if the record has dependent fields
private boolean hasDependentFields_;
// Indicates which fields have been converted to Java objects
private boolean[] isConvertedToJava_;
// Indicates which fields have been converted to server data in the as400Data_ array
private boolean[] isConvertedToAS400_;
// Name of the record
private String name_ = "";
// Array indicating if a field is null
private boolean[] nullFieldMap_;
// Use default property change support
private transient PropertyChangeSupport changes_; //@B5C
// The record format object with which this record is associated
private RecordFormat recordFormat_ = null;
// The length of the record, in bytes
int recordLength_;
// The record number of this record
int recordNumber_;
long recordNumberLong_;//@RBA
// Array to hold fields returned by getFields. This allows us to not
// instantiate a new array every time getFields is done, which allows
// us to cut down on garbage collection overhead.
Object[] returnFields_;
// The list of current veto listeners
transient private VetoableChangeSupport vetos_; //@B5A
//@B5D transient private Vector currentVetoListeners_ = new Vector();
// The list of current RecordDescriptionEvent listeners
//@B5D transient private Vector currentRecordDescriptionListeners_ = new Vector();
// The list of RecordDescriptionEvent listeners
transient private Vector recordDescriptionListeners_; //@B5C
// The list of veto listeners
//@B5D transient private Vector vetoListeners_ = new Vector();
/**
*Constructs a Record object.
**/
public Record()
{
initializeTransient(); //@B5A
}
/**
*Constructs a Record object. It uses the RecordFormat specified.
*The contents of the record will be initialized to their default values. The default
*values are determined as follows:
*
*- Use the value specified for the DFT keyword on the FieldDescription object
*contained in the RecordFormat object for a particular field.
*
- If no value was specified for the DFT keyword, use the default value from the
*AS400DataType object specified when constructing the FieldDescription object for
*a particular field.
*
*@param recordFormat Describes the contents of this record.
*@see com.ibm.as400.access.RecordFormat
**/
public Record(RecordFormat recordFormat)
{
initializeTransient(); //@B5A
initializeRecord(recordFormat);
}
/**
*Constructs a Record object. It uses the record's name and RecordFormat specified.
*The contents of the record will be initialized to their default values. The default
*values are determined as follows:
*
*- Use the value specified for the DFT keyword on the FieldDescription object for
*a particular field.
*
- If no value was specified for the DFT keyword, use the default value from the
*AS400DataType object specified when constructing the FieldDescription object for
*a particular field.
*
*@param recordFormat Describes the contents of this record.
*@param recordName The name to assign to the record.
**/
public Record(RecordFormat recordFormat, String recordName)
{
this(recordFormat);
// Verify parameters
if (recordName == null)
{
throw new NullPointerException("recordName");
}
// Set the name of the record
name_ = recordName;
}
/**
*Constructs a Record object. It uses the specified RecordFormat and a byte array
*with which to initialize the contents of the record.
*@param recordFormat Describes the contents of this record.
*@param contents The contents to which to initialize the record.
*
*Note: When using this object for the record level access classes, if
*isVariableLength()
*returns true for a field, the first two bytes of the data provided for
*that field must contain the length of the valid data. However, the number of bytes
*provided for
*the data for the field must equal the maximum field length for the field.
*@exception UnsupportedEncodingException If an error occurs when converting
*the IBM i data to a Java Object.
**/
public Record(RecordFormat recordFormat, byte[] contents)
throws UnsupportedEncodingException
{
this(recordFormat, contents, 0);
}
/**
*Constructs a Record object. It uses the specified the RecordFormat, a byte array
*from which to initialize the contents of the record and the name of the record.
*@param recordFormat Describes the contents of this record.
*@param contents The contents to which to initialize the record.
*
*Note: When using this object for the record level access classes, if isVariableLength()
*returns true for a field, the first two bytes of the data provided for
*that field must contain the length of the valid data. However, the number of bytes provided for
*the data for the field must equal the maximum field length for the field.
*@param recordName The name to assign to the record.
*@exception UnsupportedEncodingException If an error occurs when converting
*the IBM i data to a Java Object.
**/
public Record(RecordFormat recordFormat, byte[] contents, String recordName)
throws UnsupportedEncodingException
{
this(recordFormat, contents, 0, recordName);
}
/**
*Constructs a Record object. It uses the specified RecordFormat and a byte array
*from which to initialize the contents of the record.
*@param recordFormat Describes the contents of this record. The recordFormat
*must contain at least one field description.
*@param contents The contents to which to initialize the record.
*
*Note: When using this object for the record level access classes, if isVariableLength()
*returns true for a field, the first two bytes of the data provided for
*that field must contain the length of the valid data. However, the number of bytes provided for
*the data for the field must equal the maximum field length for the field.
*@param offset The offset in contents at which to start. The offset cannot
*be less than zero.
*@exception UnsupportedEncodingException If an error occurs when converting
*the IBM i data to a Java Object.
**/
public Record(RecordFormat recordFormat, byte[] contents, int offset)
throws UnsupportedEncodingException
{
initializeTransient(); //@B5A
// Verify parameters
if (recordFormat == null)
{
throw new NullPointerException("recordFormat");
}
if (recordFormat.getNumberOfFields() == 0)
{
throw new ExtendedIllegalArgumentException("recordFormat", ExtendedIllegalArgumentException.PARAMETER_VALUE_NOT_VALID);
}
if (contents == null)
{
throw new NullPointerException("contents");
}
if (contents.length == 0)
{
throw new ExtendedIllegalArgumentException("contents", ExtendedIllegalArgumentException.LENGTH_NOT_VALID);
}
if (offset < 0)
{
throw new ExtendedIllegalArgumentException("offset", ExtendedIllegalArgumentException.RANGE_NOT_VALID);
}
// Set the instance data
recordFormat_ = recordFormat;
fieldDescriptions_ = recordFormat.getFieldDescriptions();
hasDependentFields_ = recordFormat_.getHasDependentFields();
fields_ = new Object[fieldDescriptions_.length];
returnFields_ = new Object[fieldDescriptions_.length];
fieldOffsets_ = new int[fieldDescriptions_.length];
// Initialize the offset values
isConvertedToJava_ = new boolean[fieldDescriptions_.length];
isConvertedToAS400_ = new boolean[fieldDescriptions_.length];
nullFieldMap_ = new boolean[fields_.length];
FieldDescription fd = null;
int fieldOffset = 0;
int length = 0;
// Reset the record length
recordLength_ = 0;
// This loop sets the offsets for the fields and also determines the
// record length of the record.
for (int i = 0; i < fields_.length; ++i)
{
fd = fieldDescriptions_[i];
fieldOffsets_[i] = fieldOffset;
if (fd instanceof VariableLengthFieldDescription)
{
if (((VariableLengthFieldDescription)fd).isVariableLength())
{ // Add two bytes for the length of the field
fieldOffset += 2;
recordLength_ += 2;
}
}
length = fd.getDataType().getByteLength();
fieldOffset += length;
recordLength_ += length;
if (!hasDependentFields_)
{
isConvertedToAS400_[i] = true;
}
isConvertedToJava_[i] = false;
}
// Allocate the space for as400Data_ now that we know the record length
as400Data_ = new byte[recordLength_];
if (!hasDependentFields_)
{ // Go ahead and copy the contents to as400Data_
try
{
System.arraycopy(contents, offset, as400Data_, 0, as400Data_.length);
}
catch(ArrayIndexOutOfBoundsException e)
{ // Need to reset isConverted... state
for (int i = 0; i < isConvertedToAS400_.length; ++i)
{
isConvertedToAS400_[i] = false;
}
throw e;
}
}
else
{
// Initialize the contents of the record with the specified byte array
setContents(contents, offset);
}
}
/**
*Constructs a Record object. It uses the specified RecordFormat, a byte array
*from which to initialize the record's contents and the record's name.
*@param recordFormat Describes the contents of this record.
*@param contents The contents to which to initialize the record.
*
*Note: When using this object for the record level access classes, if isVariableLength()
*returns true for a field, the first two bytes of the data provided for
*that field must contain the length of the valid data. However, the number of bytes provided for
*the data for the field must equal the maximum field length for the field.
*@param offset The offset in contents at which to start. The offset cannot
*be less than zero.
*@param recordName The name to assign to the record.
*@exception UnsupportedEncodingException If an error occurs when converting
*the IBM i data to a Java Object.
**/
public Record(RecordFormat recordFormat, byte[] contents, int offset, String recordName)
throws UnsupportedEncodingException
{
this(recordFormat, contents, offset);
// Verify parameters
if (recordName == null)
{
throw new NullPointerException("recordName");
}
// Set the name
name_ = recordName;
}
/**
*Adds a listener to be notified when the value of any bound
*property is changed. The propertyChange method will be
*be called.
*@see #removePropertyChangeListener
*@param listener The PropertyChangeListener.
**/
public void addPropertyChangeListener(PropertyChangeListener listener) //@B5C
{
if (listener == null)
{
throw new NullPointerException("listener");
}
if (changes_ == null) changes_ = new PropertyChangeSupport(this);
changes_.addPropertyChangeListener(listener);
}
/**
*Adds a listener to be notified when a RecordDescriptionEvent is fired.
*@see #removeRecordDescriptionListener
*@param listener The RecordDescriptionListener.
**/
public void addRecordDescriptionListener(RecordDescriptionListener listener) //@B5C
{
if (listener == null)
{
throw new NullPointerException("listener");
}
if (recordDescriptionListeners_ == null) recordDescriptionListeners_ = new Vector();
recordDescriptionListeners_.addElement(listener);
//@B5D currentRecordDescriptionListeners_ = (Vector)recordDescriptionListeners_.clone();
}
/**
*Adds a listener to be notified when the value of any constrained
*property is changed.
*The vetoableChange method will be called.
*@see #removeVetoableChangeListener
*@param listener The VetoableChangeListener.
**/
public void addVetoableChangeListener(VetoableChangeListener listener) //@B5C
{
if (listener == null)
{
throw new NullPointerException("listener");
}
//@B5D vetoListeners_.addElement(listener);
//@B5D currentVetoListeners_ = (Vector)vetoListeners_.clone();
if (vetos_ == null) vetos_ = new VetoableChangeSupport(this);
vetos_.addVetoableChangeListener(listener); //@B5A
}
//@G0A
/**
* Tests this Record object for equality with the given object.
* @param obj The Object to compare.
* @return true if obj is a Record object and its record length, record number,
* record name, dependent fields, field values, and key field values equal this Record's;
* false otherwise. Since there are so many pieces of data that determine whether
* or not one Record equals another, the programmer may also want to consider using
* Record.toString() and comparing the Strings for equality.
**/
public boolean equals(Object obj)
{
if (obj == null) return false;
try
{
Record cmp = (Record)obj;
if (cmp.recordLength_ == recordLength_ &&
cmp.recordNumber_ == recordNumber_ &&
cmp.recordNumberLong_ == recordNumberLong_ &&//@RBA
cmp.hasDependentFields_ == hasDependentFields_ &&
(cmp.name_ == null ? (name_ == null) : cmp.name_.equals(name_)))
{
int n = getNumberOfFields();
int cn = cmp.getNumberOfFields();
if (n == cn)
{
int nk = getNumberOfKeyFields();
int cnk = getNumberOfKeyFields();
if (nk == cnk)
{
for (int i=0; i
*Note: If a field is a variable-length field, the first two bytes of data for the field
*contain the length of the valid data for the field. However, the number of bytes provided for the
*field is the maximum length of the field as specified by the FieldDescription object for the
*field in the record format for this object.
*The record format for the record must be set prior to invoking this method.
*@see Record#Record(com.ibm.as400.access.RecordFormat)
*@see Record#setRecordFormat
*@return The contents of this record.
*@exception CharConversionException If an error occurs when converting
*the contents of a field to IBM i data.
*@exception UnsupportedEncodingException If an error occurs when converting
*the contents of a field to IBM i data.
**/
public byte[] getContents()
throws CharConversionException,
UnsupportedEncodingException
{
if (recordFormat_ == null)
{
throw new ExtendedIllegalStateException("recordFormat", ExtendedIllegalStateException.PROPERTY_NOT_SET);
}
if (hasDependentFields_)
{ // If the record has dependent fields, we do the conversion now and return the contents.
// For each field in fields_, use the recordFormat_ object to get the field
// description. Use the data type object associated with the field description to translate
// the Object representing the field into bytes to be placed in the byte array.
// Repeat this process for each field.
// If the field is a variable length field (i.e the VARLEN value is greater than 0), the first
// two bytes of the data is the length of the data.
// Determine the number of bytes that make of the record
AS400DataType dType;
int offset = 0;
if (Trace.traceOn_) {
Trace.log(Trace.INFORMATION, "recordLength_: " + String.valueOf(recordLength_));
}
byte[] toBytes = new byte[recordLength_];
FieldDescription f;
int variableFieldLength;
for (int i = 0; i < fields_.length; ++i)
{ // Convert each field to server data
f = fieldDescriptions_[i];
// Check for possible variable length field
if (f instanceof VariableLengthFieldDescription)
{
if (((VariableLengthFieldDescription)f).isVariableLength())
{ // Set the two byte length portion of the contents
if (fields_[i] == null)
{
variableFieldLength = 0;
}
else
{
variableFieldLength = (f instanceof HexFieldDescription)?
((byte[])fields_[i]).length : ((String)fields_[i]).length();
}
BinaryConverter.unsignedShortToByteArray(variableFieldLength, toBytes, offset);
offset += 2;
}
}
// Whether the field is variable length or not we still write out the maximum number
// of bytes for the field. This is the required format for variable length data for record
// level access.
dType = f.getDataType();
if (fields_[i] != null)
{ // Field has a value; convert it to server data
offset += dType.toBytes(fields_[i], toBytes, offset);
}
else
{ // Field is null; use the default value for the server data to serve as a place holder for
// the field.
offset += dType.toBytes(dType.getDefaultValue(), toBytes, offset);
}
}
return toBytes;
}
// No dependent fields.
return as400Data_;
}
/**
*Writes the contents of this record to the specified output stream.
*Each field's contents will be written to out
*based on the field description for the
*field that is provided by the record format specified on construction of this object.
*The data type object for the field description will be used to do any necessary conversion
*of the contents of the field.
*Note: If a field is a variable-length field, the first two bytes of data for the field
*contain the length of the valid data for the field. However, the number of bytes provided for the
*field is the maximum length of the field as specified by the FieldDescription object for the
*field in the record format for this object.
*
*The record format for the record must be set prior to invoking this method.
*@see Record#Record(com.ibm.as400.access.RecordFormat)
*@see Record#setRecordFormat
*@param out The stream to which to write the contents of the record.
*@exception IOException If an I/O error occurs while communicating with the system.
**/
public void getContents(OutputStream out)
throws IOException
{
if (out == null)
{
throw new NullPointerException("out");
}
out.write(getContents());
}
/**
*Returns the value of the field by index.
*
*The record format for the record must be set prior to invoking this method.
*@see Record#Record(com.ibm.as400.access.RecordFormat)
*@see Record#setRecordFormat
*@param index The ordinal position of the field in the record. This value must
* be between 0 and getNumberOfFields() - 1 inclusive.
*@return The contents of the requested field.
*@exception UnsupportedEncodingException If an error occurs when converting
*the IBM i data to a Java Object.
**/
public Object getField(int index)
throws UnsupportedEncodingException
{
if (recordFormat_ == null)
{
throw new ExtendedIllegalStateException("recordFormat", ExtendedIllegalStateException.PROPERTY_NOT_SET);
}
if (index < 0 || index > fields_.length - 1)
{
throw new ExtendedIllegalArgumentException("index", ExtendedIllegalArgumentException.RANGE_NOT_VALID);
}
if (isConvertedToJava_[index])
{ // Field already converted; just return it
return fields_[index];
}
// Field has not yet been converted. We will only get here if
// the record has no dependent fields so we can go ahead and count
// on the fieldOffsets_ array being valid.
FieldDescription f = fieldDescriptions_[index];
AS400DataType dType = f.getDataType();
int variableFieldLength;
int offset = fieldOffsets_[index];
// Check for possible variable length field
if (f instanceof VariableLengthFieldDescription)
{
if (((VariableLengthFieldDescription)f).isVariableLength())
{ // Get the number of bytes returned for the field
variableFieldLength = BinaryConverter.byteArrayToUnsignedShort(as400Data_, offset);
if (f instanceof DBCSGraphicFieldDescription) //@A2A
{ //@A2A
// NOTE: The 2-byte length field in a VARGRAPHIC field is the number of "characters" and
// is NOT the number of "bytes". Each VARGRAPHIC "character" is represented by
// two bytes. So, we need to multiply the variableFieldLength by two for VARGRAPHIC.
// Note: The 2-byte length field in a VARCHAR field is the number of "bytes", so the
// variableFieldLength is correct and should not be modified.
variableFieldLength *= 2; //@A2A
} //@A2A
offset += 2;
// Convert the server data to a Java object
if ((f instanceof HexFieldDescription))
{ // Field is a hex field, no conversion is done on the data
byte[] b = new byte[variableFieldLength];
System.arraycopy(as400Data_, offset, b, 0, variableFieldLength);
fields_[index] = b;
}
else
{ // Field requires conversion based on ccsid
//@B5D Converter c = new Converter(((AS400Text)dType).getCcsid()); //@B5C
ConverterImpl c = ((AS400Text)dType).getConverter(); //@B5A @F0C
fields_[index] = c.byteArrayToString(as400Data_, offset, variableFieldLength);
}
}
else
{
// Field is not variable length
fields_[index] = dType.toObject(as400Data_, offset);
}
}
else
{
// Not a VariableLengthFieldDescription
fields_[index] = dType.toObject(as400Data_, offset);
}
if (recordDescriptionListeners_ != null) fireFieldModifiedEvent();
isConvertedToJava_[index] = true;
return fields_[index];
}
/**
*Returns the value of the field by name.
*
*The record format for the record must be set prior to invoking this method.
*@see Record#Record(com.ibm.as400.access.RecordFormat)
*@see Record#setRecordFormat
*@param name The name of the field.
*@return The contents of the requested field.
*@exception UnsupportedEncodingException If an error occurs when converting
*the IBM i data to a Java Object.
**/
public Object getField(String name)
throws UnsupportedEncodingException
{
if (recordFormat_ == null)
{
throw new ExtendedIllegalStateException("recordFormat", ExtendedIllegalStateException.PROPERTY_NOT_SET);
}
return getField(recordFormat_.getIndexOfFieldName(name));
}
/**
*Returns the value of the field by index, as an unconverted byte array.
*
*The record format for the record must be set prior to invoking this method.
*@see Record#Record(com.ibm.as400.access.RecordFormat)
*@see Record#setRecordFormat
*@param index The ordinal position of the field in the record. This value must
* be between 0 and getNumberOfFields() - 1 inclusive.
*@return The unconverted contents of the requested field.
**/
public byte[] getFieldAsBytes(int index)
{
if (recordFormat_ == null)
{
throw new ExtendedIllegalStateException("recordFormat", ExtendedIllegalStateException.PROPERTY_NOT_SET);
}
if (index < 0 || index > fields_.length - 1)
{
throw new ExtendedIllegalArgumentException("index", ExtendedIllegalArgumentException.RANGE_NOT_VALID);
}
byte[] fieldAsBytes = null;
int fieldOffset = 0; // offset to start of field in as400Data_
int fieldByteLength = 0; // length of field, including length bytes if any
if (hasDependentFields_) // The record has dependent fields, so fieldOffsets_ is unreliable.
{
// For each field description in the recordFormat_ object, until we reach the field of interest, determine the field offset and length.
// If a field is a variable length field, we must account for the two bytes worth of length data which precede the actual data for the field.
int offsetToNextField = 0;
for (int i = 0; i <= index; ++i)
{
fieldOffset = offsetToNextField;
FieldDescription f = fieldDescriptions_[i];
AS400DataType dType = f.getDataType();
fieldByteLength = dType.getByteLength();
int lengthDependField = recordFormat_.getLengthDependency(i);
int offsetDependField = recordFormat_.getOffsetDependency(i);
// Check for offset dependent field
if (offsetDependField != -1)
{ // Set offset to value specified in the field this field depends on
fieldOffset = ((Number)fields_[offsetDependField]).intValue();
}
if (lengthDependField != -1)
{
// The length of this field is contained in the field that this field depends on.
// Because the field depended on must exist prior to this field in the byte array,
// its value has already been determined.
fieldByteLength = ((Number)fields_[lengthDependField]).intValue();
}
// Check for possible variable length field
if (f instanceof VariableLengthFieldDescription &&
((VariableLengthFieldDescription)f).isVariableLength())
{
fieldByteLength += 2; // allow for the 2 leading "length bytes"
}
// Prepare to examine the next field.
offsetToNextField = fieldOffset + fieldByteLength;
} // for ...
} // if ...
else // no dependent fields, so fieldOffsets_ is reliable
{
fieldOffset = fieldOffsets_[index];
FieldDescription f = fieldDescriptions_[index];
AS400DataType dType = f.getDataType();
fieldByteLength = dType.getByteLength();
// Check for possible variable length field.
if (f instanceof VariableLengthFieldDescription &&
((VariableLengthFieldDescription)f).isVariableLength())
{ // Get the number of bytes returned for the field.
// Whether the field is variable length or not we still write out the maximum number
// of bytes for the field. This is the required format for variable length data for record level access.
fieldByteLength += 2; // allow for the 2 leading "length bytes"
}
}
fieldAsBytes = new byte[fieldByteLength];
System.arraycopy(as400Data_, fieldOffset, fieldAsBytes, 0, fieldAsBytes.length);
return fieldAsBytes;
}
/**
*Returns the value of the field by name, as an unconverted byte array.
*
*The record format for the record must be set prior to invoking this method.
*@see Record#Record(com.ibm.as400.access.RecordFormat)
*@see Record#setRecordFormat
*@param name The name of the field.
*@return The unconverted contents of the requested field.
**/
public byte[] getFieldAsBytes(String name)
{
if (recordFormat_ == null)
{
throw new ExtendedIllegalStateException("recordFormat", ExtendedIllegalStateException.PROPERTY_NOT_SET);
}
return getFieldAsBytes(recordFormat_.getIndexOfFieldName(name));
}
/**
*Returns the values of the fields in the record.
*@return The values of the fields in the record. An array of size zero is
*returned if the record format has not been set.
*@exception UnsupportedEncodingException If an error occurs when converting
*the IBM i data to a Java Object.
**/
public Object[] getFields()
throws UnsupportedEncodingException
{
if (recordFormat_ == null)
{
return new Object[0];
}
// Get each field individually in the event that conversion has not yet been done.
for (int i = 0; i < fields_.length; ++i)
{
returnFields_[i] = getField(i);
}
return returnFields_;
}
/**
*Returns the values of the key fields in the record.
*@return The values of the key fields in the record.
*An array of length 0 is returned if the record format has not been set
*or if no key fields exist.
*@exception UnsupportedEncodingException If an error occurs when converting
*the IBM i data to a Java Object.
**/
public Object[] getKeyFields()
throws UnsupportedEncodingException
{
if (recordFormat_ == null)
{
return new Object[0];
}
Object[] keyFields = new Object[recordFormat_.getNumberOfKeyFields()];
String[] keyFieldNames = recordFormat_.getKeyFieldNames();
for (int i = 0; i < keyFields.length; ++i)
{
keyFields[i] = getField(keyFieldNames[i]);
}
return keyFields;
}
/**
*Returns the values of the key fields in a byte array.
*@return The values of the key fields in a byte array.
*A byte array of length 0 is returned if the record format has not been set
*or if no key fields exist.
**/
public byte[] getKeyFieldsAsBytes()
{
if (recordFormat_ == null)
{
return new byte[0];
}
ByteArrayOutputStream keyAsBytes = new ByteArrayOutputStream();
String[] keyFieldNames = recordFormat_.getKeyFieldNames();
AS400DataType dt = null;
FieldDescription fd = null;
int length;
int index;
for (int i = 0; i < keyFieldNames.length; ++i)
{
index = recordFormat_.getIndexOfFieldName(keyFieldNames[i]);
fd = fieldDescriptions_[index];
dt = fd.getDataType();
length = dt.getByteLength();
if (fd instanceof VariableLengthFieldDescription && ((VariableLengthFieldDescription)fd).isVariableLength())
{
length += 2;
}
keyAsBytes.write(as400Data_, fieldOffsets_[index], length);
}
return keyAsBytes.toByteArray();
}
/**
*Returns the number of fields in this record.
*@return The number of fields in this record. Zero is returned if the record
*format has not been set.
**/
public int getNumberOfFields()
{
return (recordFormat_ == null)? 0 : fields_.length;
}
/**
*Returns the number of key fields in this record.
*@return The number of key fields in this record. Zero is returned if the record
*format has not been set.
**/
public int getNumberOfKeyFields()
{
return (recordFormat_ == null)? 0 : recordFormat_.getNumberOfKeyFields();
}
/**
*Returns the record format for this record.
*@return The record format for this record. If the record format has
*not been set, null is returned.
**/
public RecordFormat getRecordFormat()
{
return recordFormat_;
}
/**
*Returns the record length of this record.
*@return The record length of this record. Zero is returned if the record format
*for this object has not been set.
**/
public int getRecordLength()
{
return recordLength_;
}
/**
*Returns the record name for this record.
*@return The name of this record. If the name has not been set,
*an empty string is returned.
**/
public String getRecordName()
{
return name_;
}
/**
*Returns the record number of this record. This method only pertains to the
*record level access classes.
*@return The record number of this record. Zero is returned if no record number has been set.
**/
public int getRecordNumber()
{
return recordNumber_;
}
//@RBA
/**
*Returns the record number in long type of this record. This method only pertains to the
*record level access classes.
*@return The record number of this record. Zero is returned if no record number has been set.
**/
public long getRecordNumberLong()
{
return recordNumberLong_;
}
//@G0A
/**
* Returns a hash code value for this Record. This is useful if Record objects
* need to be placed into Hashtables.
* @return The hash code.
**/
public int hashCode()
{
return recordNumber_ == 0 ? recordLength_ : recordNumber_;
}
/**
*Initializes this record to its default values based on the specified record format.
*@param recordFormat The record format for this record.
**/
private void initializeRecord(RecordFormat recordFormat)
{
// Verify parameters
if (recordFormat == null)
{
throw new NullPointerException("recordFormat");
}
if (recordFormat.getNumberOfFields() == 0)
{
throw new ExtendedIllegalArgumentException("recordFormat", ExtendedIllegalArgumentException.PARAMETER_VALUE_NOT_VALID);
}
// Set the instance data
recordFormat_ = recordFormat;
fieldDescriptions_ = recordFormat.getFieldDescriptions();
hasDependentFields_ = recordFormat_.getHasDependentFields();
fields_ = new Object[fieldDescriptions_.length];
returnFields_ = new Object[fieldDescriptions_.length];
fieldOffsets_ = new int[fieldDescriptions_.length];
isConvertedToJava_ = new boolean[fieldDescriptions_.length];
isConvertedToAS400_ = new boolean[fieldDescriptions_.length];
nullFieldMap_ = new boolean[fieldDescriptions_.length];
// Initialize the contents of the record to the fieldDescription's default value.
// Initialize the nullFieldMap_ to false values. Initialize the fieldOffsets_ array
// to the appropriate offset.
Object obj;
FieldDescription fd = null;
AS400DataType dType = null;
byte[] lenAsBytes = new byte[2];
int offset = 0;
int variableFieldLength;
ByteArrayOutputStream b = new ByteArrayOutputStream();
// Reset recordLength_
recordLength_ = 0;
for (int i = 0; i < fields_.length; ++i)
{
// Get the default value for this field
fd = fieldDescriptions_[i];
obj = fd.getDFT();
// Set the offset of this field
fieldOffsets_[i] = offset;
// Set the Java value of the field
// @B0C: Check for DFT of current or null
if (obj == null) // DFT was not set, or was set to null or current
{
if (fd.isDFTNull()) // DFT was set to null => write 'null' to the field
{
fields_[i] = fd.getDataType().getDefaultValue();
if (fieldDescriptions_[i].getALWNULL())
nullFieldMap_[i] = true;
else
nullFieldMap_[i] = false;
}
else if (fd.isDFTCurrent()) // DFT was set to current => write the appropriate value
{
fields_[i] = fd.getDFTCurrentValue();
}
else // DFT was not set => write 'null' to the field
{
fields_[i] = fd.getDataType().getDefaultValue();
if (fieldDescriptions_[i].getALWNULL())
{
nullFieldMap_[i] = true;
fields_[i] = null; //@B1A Set the field value to null as well.
}
else
nullFieldMap_[i] = false;
}
}
else
{
fields_[i] = obj; // DFT was set => write the default value
}
// Check for possible variable length field
if (fd instanceof VariableLengthFieldDescription)
{
if (((VariableLengthFieldDescription)fd).isVariableLength())
{ // Set the two byte length portion of the contents
if (obj == null)
{
variableFieldLength = 0;
}
else
{
variableFieldLength = (fd instanceof HexFieldDescription)?
((byte[])obj).length : ((String)obj).length();
}
BinaryConverter.unsignedShortToByteArray(variableFieldLength, lenAsBytes, 0);
b.write(lenAsBytes, 0, 2);
offset += 2;
recordLength_ += 2;
}
}
// Whether the field is variable length or not we still write out the maximum number
// of bytes for the field. This is the required format for variable length data for record
// level access.
dType = fd.getDataType();
if (fields_[i] != null) //@B1A
{ // Field has a value; convert it to server data
b.write(dType.toBytes(fields_[i]), 0, dType.getByteLength());
}
else //@B1A
{ // Field is null; use the default value for the server data to serve as a place holder for
// the field.
b.write(dType.toBytes(dType.getDefaultValue()), 0, dType.getByteLength()); //@B1A
}
// Indicate the field is in a converted state
isConvertedToJava_[i] = true;
isConvertedToAS400_[i] = true;
// Determine the next offset value and increment the record length appropriately
offset += fd.getDataType().getByteLength();
recordLength_ += fd.getDataType().getByteLength();
}
// Allocate the space for as400Data_
as400Data_ = b.toByteArray();
if (recordDescriptionListeners_ != null) fireFieldModifiedEvent();
}
//@D0A
void initializeTextObjects(AS400 system)
{
// First do our record format
if (recordFormat_ != null) recordFormat_.initializeTextObjects(system);
// Then do all of our internal fields
if (fieldDescriptions_ != null)
{
for (int i=0; i
*The record format for the record must be set prior to invoking this method.
*@see Record#Record(com.ibm.as400.access.RecordFormat)
*@see Record#setRecordFormat
*@param index The index of the field. The index must be between
*0 and getNumberOfFields() - 1.
*@return true if the field is null; false otherwise.
**/
public boolean isNullField(int index)
{
if (recordFormat_ == null)
{
throw new ExtendedIllegalStateException("recordFormat", ExtendedIllegalStateException.PROPERTY_NOT_SET);
}
if (index < 0 || index > fields_.length - 1)
{
throw new ExtendedIllegalArgumentException("index", ExtendedIllegalArgumentException.RANGE_NOT_VALID);
}
return nullFieldMap_[index];
}
/**
*Indicates if the field is null.
*
*The record format for the record must be set prior to invoking this method.
*@see Record#Record(com.ibm.as400.access.RecordFormat)
*@see Record#setRecordFormat
*@param name The name of the field.
*@return true if the field is null; false otherwise.
**/
public boolean isNullField(String name)
{
if (recordFormat_ == null)
{
throw new ExtendedIllegalStateException("recordFormat", ExtendedIllegalStateException.PROPERTY_NOT_SET);
}
return nullFieldMap_[recordFormat_.getIndexOfFieldName(name)];
}
/**
*Reads the number of bytes requested. This method will loop until
*either length bytes have been read or until the end of file is reached.
*@param in The Inputstream from which to read.
*@param buf The buffer from which to read the data.
*@param offset The offset within buf array from which to start reading.
*@param length The number of bytes to read.
*@returns The number of bytes read.
*@exception IOException If an I/O error occurs while communicating with the system.
**/
private int readFromStream(InputStream in, byte[] buf, int offset, int length)
throws IOException
{
boolean endOfFile = false;
int bytesRead = 0;
while ((bytesRead < length) && !endOfFile)
{
int temp = in.read(buf, offset+bytesRead, length - bytesRead);
if (temp == -1)
{
endOfFile = true;
}
else
{
bytesRead += temp;
}
}
return bytesRead;
}
/**
*Overrides the ObjectInputStream.readObject() method in order to return any
*transient parts of the object to there properly initialized state.
* I.e we in effect
*call the null constructor. By calling ObjectInputStream.defaultReadObject()
*we restore the state of any non-static and non-transient variables. We
*then continue on to restore the state (as necessary) of the remaining varaibles.
*@param in The input stream from which to deserialize the object.
*@exception ClassNotFoundException If the class being deserialized is not found.
*@exception IOException If an error occurs while communicating with the system.
**/
private void readObject(java.io.ObjectInputStream in)
throws ClassNotFoundException,
IOException
{
in.defaultReadObject();
initializeTransient(); //@B5A
//@B5D currentVetoListeners_ = new Vector();
//@B5D currentRecordDescriptionListeners_ = new Vector();
//@B5D recordDescriptionListeners_ = new Vector();
//@B5D vetoListeners_ = new Vector();
}
/**
*Removes a listener from the change list.
*If the listener is not on the list, do nothing.
*@see #addPropertyChangeListener
*@param listener The PropertyChangeListener.
**/
public void removePropertyChangeListener(PropertyChangeListener listener) //@B5C
{
if (listener == null)
{
throw new NullPointerException("listener");
}
if (changes_ != null) changes_.removePropertyChangeListener(listener);
}
/**
*Removes a listener from the record description listeners list.
*If the listener is not on the list, do nothing.
*@see #addRecordDescriptionListener
*@param listener The RecordDescriptionListener.
**/
public void removeRecordDescriptionListener(RecordDescriptionListener listener) //@B5C
{
if (listener == null)
{
throw new NullPointerException("listener");
}
if (recordDescriptionListeners_ != null) recordDescriptionListeners_.removeElement(listener);
//@B5D currentRecordDescriptionListeners_ = (Vector)recordDescriptionListeners_.clone();
}
/**
*Removes a listener from the veto change listeners list.
*If the listener is not on the list, do nothing.
*@see #addVetoableChangeListener
*@param listener The VetoableChangeListener.
**/
public void removeVetoableChangeListener(VetoableChangeListener listener) //@B5C
{
if (listener == null)
{
throw new NullPointerException("listener");
}
//@B5D vetoListeners_.removeElement(listener);
//@B5D currentVetoListeners_ = (Vector)vetoListeners_.clone();
if (vetos_ != null) vetos_.removeVetoableChangeListener(listener); //@B5A
}
/**
*Sets the contents of this record from the specified byte array.
*The contents of each field will be set from contents
*based on the field description for the
*field that is provided by the record format specified on construction of this object.
*The data type object for the field description will be used to do any necessary conversion
*of the data from the byte array.
*Note: When using this object for the record level access classes, if isVariableLength()
*returns true for a field, the first two bytes of the data provided for
*that field must contain the length of the valid data. However, the number of bytes provided for
*the data for the field must equal the maximum field length for the field.
*
*The record format for the record must be set prior to invoking this method.
*@see Record#Record(com.ibm.as400.access.RecordFormat)
*@see Record#setRecordFormat
*@param contents The data with which to set the contents of this record.
*@exception UnsupportedEncodingException If an error occurs when converting
*the IBM i data to a Java Object.
**/
public void setContents(byte[] contents)
throws UnsupportedEncodingException
{
setContents(contents, 0);
}
/**
*Sets the contents of this record from the specified byte array.
*The contents of each field will be set from contents
*based on the field description for the
*field that is provided by the record format specified on construction of this object.
*The data type object for the field description will be used to do any necessary conversion
*of the data from the byte array.
*Note: When using this object for the record level access classes, if isVariableLength()
*returns true for a field, the first two bytes of the data provided for
*that field must contain the length of the valid data. However, the number of bytes provided for
*the data for the field must equal the maximum field length for the field.
*
*The record format for the record must be set prior to invoking this method.
*@see Record#Record(com.ibm.as400.access.RecordFormat)
*@see Record#setRecordFormat
*@param contents The data with which to set the contents of this record.
*@param offset The offset in contents at which to start.
*@exception UnsupportedEncodingException If an error occurs when converting
*the IBM i data to a Java Object.
**/
public void setContents(byte[] contents, int offset)
throws UnsupportedEncodingException
{
if (recordFormat_ == null)
{
throw new ExtendedIllegalStateException("recordFormat", ExtendedIllegalStateException.PROPERTY_NOT_SET);
}
if (contents == null)
{
throw new NullPointerException("contents");
}
if (contents.length == 0)
{
throw new ExtendedIllegalArgumentException("contents", ExtendedIllegalArgumentException.LENGTH_NOT_VALID);
}
if (offset < 0 || offset >= contents.length)
{
throw new ExtendedIllegalArgumentException("offset (" + offset + ")", ExtendedIllegalArgumentException.RANGE_NOT_VALID);
}
if (hasDependentFields_)
{ // Record has dependent fields; convert now.
// For each field description in the recordFormat_ object, use the field description's
// data type object to translate the appropriate number of bytes in contents to an Object.
// Repeat this process for each field description in the record format.
// If the field is a variable length field, we must account for the two bytes worth of length
// data which precede the actual data for the field.
AS400DataType dType;
int numFields = recordFormat_.getNumberOfFields();
FieldDescription f;
int lengthDependField;
int offsetDependField;
int variableFieldLength;
recordLength_ = 0; // Reset the record length
for (int i = 0; i < numFields; ++i)
{
f = fieldDescriptions_[i];
lengthDependField = recordFormat_.getLengthDependency(i);
offsetDependField = recordFormat_.getOffsetDependency(i);
dType = f.getDataType();
int length = dType.getByteLength();
// Check for offset dependent field
if (offsetDependField != -1)
{ // Set offset to value specified in the field this field depends on
offset = ((Number)fields_[offsetDependField]).intValue();
}
if (lengthDependField != -1)
{
AS400DataType newDataType = null;
// The length of this field is contained in the field that this field depends on
// Because the field depended on must exist prior to this field in the byte array,
// its value has already been determined.
length = ((Number)fields_[lengthDependField]).intValue();
// @A1A: Check if f is variable length.. If so
// we need to bump the offset by two
// to get to the actual data and bump the record length by two.
boolean varLen = false;
if (f instanceof VariableLengthFieldDescription && ((VariableLengthFieldDescription)f).isVariableLength())
{
offset += 2;
recordLength_ += 2;
varLen = true;
}
// End @A1A
// Convert the server data to a Java object
if (f instanceof HexFieldDescription)
{ // Field is a hex field, setDataType to indicate correct length
newDataType = new AS400ByteArray(length);
}
else if (f instanceof ArrayFieldDescription)
{
newDataType = new AS400Array(((AS400Array)dType).getType(), length);
}
else
{ // character field - setDataType to indicate correct length
AS400Text dtText = (AS400Text)dType; //@B6A
//@B6D newDataType = new AS400Text(length, ((AS400Text)dType).getCcsid());
newDataType = new AS400Text(length, dtText.getCcsid()); //@F0C
((AS400Text)newDataType).setConverter(dtText.getConverter()); //@F0C
}
if (!varLen) //@A1A: If field is variable length need to preserve
{ // maximum field length
f.setDataType(newDataType);
}
fields_[i] = newDataType.toObject(contents, offset);
recordLength_ += f.getDataType().getByteLength();
}
// Check for possible variable length field
else if (f instanceof VariableLengthFieldDescription)
{
if (((VariableLengthFieldDescription)f).isVariableLength())
{ // Get the number of bytes returned for the field
variableFieldLength = BinaryConverter.byteArrayToUnsignedShort(contents, offset);
offset += 2;
recordLength_ += 2;
// Convert the server data to a Java object
if ((f instanceof HexFieldDescription))
{ // Field is a hex field, no conversion is done on the data
byte[] b = new byte[variableFieldLength];
System.arraycopy(contents, offset, b, 0, variableFieldLength);
fields_[i] = b;
}
else
{ // Field requires conversion based on ccsid
//@B5D Converter c = new Converter(((AS400Text)dType).getCcsid()); //@B5C
ConverterImpl c = ((AS400Text)dType).getConverter(); //@B5A @F0C
fields_[i] = c.byteArrayToString(contents, offset, variableFieldLength);
}
recordLength_ += dType.getByteLength();
}
else
{ // Field is not variable length
fields_[i] = dType.toObject(contents, offset);
recordLength_ += dType.getByteLength();
}
}
else
{ // Not a VariableLengthFieldDescription
fields_[i] = dType.toObject(contents, offset);
recordLength_ += dType.getByteLength();
}
// Whether the field is variable length or not, we are always given the maximum
// number of bytes for the field in the byte array.
offset += length;
isConvertedToJava_[i] = true;
isConvertedToAS400_[i] = false;
}
if (recordDescriptionListeners_ != null) fireFieldModifiedEvent();
}
else
{ // No dependent fields; we can convert on the fly as necessary
if (contents.length - offset < as400Data_.length)
{
Trace.log(Trace.ERROR, "Byte array has insufficient length for record. contents length: " + contents.length + ", offset: " + offset + ", record length: " + as400Data_.length);
throw new ExtendedIllegalArgumentException("contents.length (" + contents.length + "), offset (" + offset + "), recordLength (" + as400Data_.length + ")", ExtendedIllegalArgumentException.RANGE_NOT_VALID);
}
System.arraycopy(contents, offset, as400Data_, 0, as400Data_.length);
// Indicate that no fields have been converted yet
for (int i = 0; i < isConvertedToJava_.length; ++i)
{
isConvertedToJava_[i] = false;
isConvertedToAS400_[i] = true;
}
}
}
/**
*Sets the contents of this record from the specified input stream.
*The contents of each field will be set from in based on the field description for the
*field that is provided by the record format specified on construction of this object.
*The data type object for the field description will be used to do any necessary conversion
*of the data from the input stream.
*Note: When using this object for the record level access classes, if isVariableLength()
*returns true for a field, the first two bytes of the data provided for
*that field must contain the length of the data.
*
*The record format for the record must be set prior to invoking this method.
*@see Record#Record(com.ibm.as400.access.RecordFormat)
*@see Record#setRecordFormat
*@param in The stream from which to read the data.
*@exception IOException If an I/O error occurs while communicating with the system.
**/
public void setContents(InputStream in)
throws IOException
{
if (recordFormat_ == null)
{
throw new ExtendedIllegalStateException("recordFormat", ExtendedIllegalStateException.PROPERTY_NOT_SET);
}
if (in == null)
{
throw new NullPointerException("in");
}
AS400DataType dType;
byte[] contents = new byte[recordLength_];
if (readFromStream(in, contents, 0, recordLength_) != recordLength_)
{
throw new ExtendedIOException("Unable to read " + String.valueOf(recordLength_) + "bytes", ExtendedIOException.UNKNOWN_ERROR);
}
setContents(contents, 0);
}
/**
*Sets the contents of the field at index to value.
*
*The record format for the record must be set prior to invoking this method.
*@see Record#Record(com.ibm.as400.access.RecordFormat)
*@see Record#setRecordFormat
*@param index The position in this record of the field whose contents are to be set. The index must be between 0 and getNumberOfFields() - 1.
*@param value The value to which to set the contents of the field. Specify null for
*value to indicate that the field is null.
**/
public void setField(int index, Object value)
{
if (recordFormat_ == null)
{
throw new ExtendedIllegalStateException("recordFormat", ExtendedIllegalStateException.PROPERTY_NOT_SET);
}
if (index < 0 || index > fields_.length - 1)
{
throw new ExtendedIllegalArgumentException("index", ExtendedIllegalArgumentException.RANGE_NOT_VALID);
}
fields_[index] = value;
if (recordDescriptionListeners_ != null) fireFieldModifiedEvent();
if (value == null)
{
nullFieldMap_[index] = true;
}
//@B0A
else
{
nullFieldMap_[index] = false;
}
isConvertedToJava_[index] = true;
byte[] convertedFieldBytes = null; //@A2A
if (!hasDependentFields_)
{ // Keep the contents of as400Data_ up to date so that
// getContents does not need to do any translation
int offset = fieldOffsets_[index];
int variableFieldLength=0; //Initialize @A2C
FieldDescription f = fieldDescriptions_[index];
// Check for possible variable length field
if (f instanceof VariableLengthFieldDescription)
{
if (((VariableLengthFieldDescription)f).isVariableLength())
{
// Set the two byte length portion of the contents
if (fields_[index] == null)
{
// variableFieldLength = 0; Already set to zero, so no-op //@A2D
}
else
{
try { //@A2A
// For variable length fields there is a two-byte length field that
// needs to be calculated. Cannot simply use a String.length() method
// on the input parameter "value", because it may need to be converted
// to the ccsid of the target sytem which could result in a different
// length string (i.e. DBCS which could add shift-in and shift-out
// characters). Unicode "characters" may be represented by multiple
// "bytes", hence the need to carefully calculate the "number of bytes"
// for the variableFieldLength (not the number of characters).
// Therefore, extract the ccsid, convert the data, and save the length
// of the result in variableFieldLength.
AS400DataType tmpDataType = f.getDataType(); //@A2A
if (tmpDataType instanceof AS400Text) //@A2A
{ //@A2A
int tmpCcsid = ((AS400Text)tmpDataType).getCcsid(); //@A2A
convertedFieldBytes = CharConverter.stringToByteArray(tmpCcsid, (String)fields_[index]); //@A2A
variableFieldLength = convertedFieldBytes.length; //@A2A
} //@A2A
else //@A2A
{ //@A2A
// Prior to the @A2 fix, the following line of code was used to
// calculate the string length. It is valid for non-AS400Text
// data types. Retain this behavior.
variableFieldLength = (f instanceof HexFieldDescription)?
((byte[])fields_[index]).length : ((String)fields_[index]).length(); //@A2C
} //@A2A
if (f instanceof DBCSGraphicFieldDescription) //@A2A
{ //@A2A
// NOTE: The 2-byte length field in a VARGRAPHIC field is the number of "characters" and
// is NOT the number of "bytes". Each VARGRAPHIC "character" is represented by
// two bytes. So, we need to divide the variableFieldLength by two for VARGRAPHIC.
// Note: The 2-byte length field in a VARCHAR field is the number of "bytes", so the
// variableFieldLength is correct and should not be modified.
variableFieldLength /= 2; //@A2A
} //@A2A
} //@A2A
catch(UnsupportedEncodingException e) //@A2A
{
Trace.log(Trace.ERROR, "Record.setField received UnsupportedEncodingException", e);
throw new
InternalErrorException(InternalErrorException.UNEXPECTED_EXCEPTION);//@A2A
}
}
BinaryConverter.unsignedShortToByteArray(variableFieldLength, as400Data_, offset);
offset += 2;
}
}
// Whether the field is variable length or not we still write out the maximum number
// of bytes for the field. This is the required format for variable length data for record
// level access.
AS400DataType dType = f.getDataType();
if (fields_[index] != null)
{
if (convertedFieldBytes != null) //@A2A
{
// Use already converted data rather than re-converting the data
System.arraycopy(convertedFieldBytes, 0, as400Data_, offset, convertedFieldBytes.length);//@A2A
}
else
{
// Field has a value; convert it to server data
dType.toBytes(fields_[index], as400Data_, offset);
}
}
else
{ // Field is null; use the default value for the server data to serve as a place holder for
// the field.
dType.toBytes(dType.getDefaultValue(), as400Data_, offset);
}
// Indicate the field is in a converted state
isConvertedToAS400_[index] = true;
}
else
{
isConvertedToAS400_[index] = false;
}
}
/**
*Sets the contents of the field with the specified name to value.
*
*The record format for the record must be set prior to invoking this method.
*@see Record#Record(com.ibm.as400.access.RecordFormat)
*@see Record#setRecordFormat
*@param name The name of the field whose contents are to be set.
*@param value The value to which to set the contents of the field. Specify null for
*value to indicate that the field is null.
**/
public void setField(String name, Object value)
{
if (recordFormat_ == null)
{
throw new ExtendedIllegalStateException("recordFormat", ExtendedIllegalStateException.PROPERTY_NOT_SET);
}
setField(recordFormat_.getIndexOfFieldName(name), value);
}
/**
*Sets the record format for this record.
*@param recordFormat The record format for this record.
*@exception PropertyVetoException If a change is vetoed.
**/
public void setRecordFormat(RecordFormat recordFormat)
throws PropertyVetoException
{
if (recordFormat == null)
{
throw new NullPointerException("recordFormat");
}
//@B5C - fire events the "new" way
// Notify veto listeners of the change
if (vetos_ != null) vetos_.fireVetoableChange("recordFormat", recordFormat_, recordFormat);
RecordFormat old = recordFormat_;
initializeRecord(recordFormat);
if (changes_ != null) changes_.firePropertyChange("recordFormat", old, recordFormat_);
}
/**
*Sets the name for this record.
*@param name The name for this record.
*@exception PropertyVetoException If a change is vetoed.
**/
public void setRecordName(String name)
throws PropertyVetoException
{
if (name == null)
{
throw new NullPointerException("name");
}
//@B5C - fire events the "new" way
// Notify veto listeners of the change
if (vetos_ != null) vetos_.fireVetoableChange("recordName", name_, name);
String old = name_;
name_ = name;
if (changes_ != null) changes_.firePropertyChange("recordName", old, name_);
}
/**
*Sets the record number of this record. This method only pertains to the record
*level access class SequentialFile when a write or update by record number
*is being done.
*@param recordNumber The record number of this record. The
*recordNumber must be greater than 0.
*@exception PropertyVetoException If a change is vetoed.
**/
public void setRecordNumber(int recordNumber)
throws PropertyVetoException
{
if (recordNumber < 0)
{
throw new ExtendedIllegalArgumentException("recordNumber", ExtendedIllegalArgumentException.RANGE_NOT_VALID);
}
//@B5C - fire events the "new" way
// Notify veto listeners of the change
Integer old = null;
Integer newnum = null;
if (vetos_ != null || changes_ != null)
{
old = new Integer(recordNumber_);
newnum = new Integer(recordNumber);
}
if (vetos_ != null) vetos_.fireVetoableChange("recordNumber", old, newnum);
recordNumber_ = recordNumber;
if (changes_ != null) changes_.firePropertyChange("recordNumber", old, newnum);
}
//@RBA
/**
* Sets the record number with long type of this record.
* @param recordNumber
* @throws PropertyVetoException If the recipient wishes the property change to be rolled back.
*/
public void setRecordNumberLong(long recordNumber)
throws PropertyVetoException
{
if (recordNumber > 4294967288L ||recordNumber < 0)
{
throw new ExtendedIllegalArgumentException("recordNumber", ExtendedIllegalArgumentException.RANGE_NOT_VALID);
}
//@B5C - fire events the "new" way
// Notify veto listeners of the change
Long old = null;
Long newnum = null;
if (vetos_ != null || changes_ != null)
{
old = new Long(recordNumberLong_);
newnum = new Long(recordNumber);
}
if (vetos_ != null) vetos_.fireVetoableChange("recordNumberLong_", old, newnum);
recordNumberLong_ = recordNumber;
if (changes_ != null) changes_.firePropertyChange("recordNumberLong_", old, newnum);
}
/**
*Returns the contents of this record formatted as a String. If a field is null,
*"null" is substituted for the contents of the field in the string representation
*of this record.
*@return The contents of this record. The empty string is returned if the
*record has not contents.
**/
public String toString()
{
if (recordFormat_ == null)
{
return "";
}
StringBuffer theRecord = new StringBuffer(0);
Object obj = null;
for (int i = 0; i < fields_.length; ++i)
{ // Append each field as a String to theRecord. Separate each field's
// contents with a single space.
try
{
obj = getField(i);
}
catch(UnsupportedEncodingException e)
{
// Unable to convert field; set to null. We do this because
// we can't throw an exception from toString()
obj = null;
}
catch(Exception e) //@D0A
{
// Some other exception; probably due to the fact that
// this Record object hasn't had its AS400Text objects
// filled in.
obj = "???"; //@D0A
}
if (obj == null)
{
theRecord.append("null");
}
else
{
if (obj instanceof byte[])
{
theRecord.append(new String((byte[])obj));
}
else
{
theRecord.append(obj.toString());
}
}
theRecord.append(" ");
}
// We return all but the last character which is the last blank we added
return theRecord.toString().substring(0, theRecord.length() - 1);
}
}