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 Show documentation
Show all versions of jt400 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 = Integer.valueOf(recordNumber_);
newnum = Integer.valueOf(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 = Long.valueOf(recordNumberLong_);
newnum = Long.valueOf(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);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy