src.com.ibm.as400.data.PcmlDataValues 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
///////////////////////////////////////////////////////////////////////////////
//
// JTOpen (IBM Toolbox for Java - OSS version)
//
// Filename: PcmlDataValues.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-2000 International Business Machines Corporation and
// others. All rights reserved.
//
///////////////////////////////////////////////////////////////////////////////
package com.ibm.as400.data;
import com.ibm.as400.access.AS400DataType;
import com.ibm.as400.access.AS400Text;
import com.ibm.as400.access.AS400Date;
import com.ibm.as400.access.AS400Time;
import com.ibm.as400.access.AS400Timestamp;
import com.ibm.as400.access.BidiStringType;
import com.ibm.as400.access.BinaryConverter;
import com.ibm.as400.access.Trace; // @D3A
import java.math.BigDecimal;
import java.math.BigInteger;
import java.io.IOException; // @C1A
import java.io.ObjectInputStream; // @C1A
import java.io.ObjectOutputStream; // @C1A
import java.io.OutputStream;
import java.io.Serializable; // @C1A
import java.util.Hashtable;
import java.util.StringTokenizer;
import java.util.TimeZone;
class PcmlDataValues extends Object implements Serializable // @C1C
{
static final long serialVersionUID = -8169008879805188674L; // @C1A
private PcmlData m_owner; // PcmlData node that owns this object
private PcmlDimensions m_indices; // Indices into owning PcmlNode's vectors of PcmlDataValues
private Object m_value; // Java native value: (String, Short, Integer, Long, Float, Double, BigDecimal. byte[])
private long m_valueTs; // Correlation id of Java native value from PcmlDocument.getCorrelationID()
private byte[] m_bytes; // IBM i bytes (ebcdic/big-endian)
private long m_bytesTs; // Correlation id of IBM i bytes from PcmlDocument.getCorrelationID()
private int m_bidiStringType; // Type of string that is contained in the value @C6A
// Default constructor
private PcmlDataValues()
{
m_value = null;
m_bytes = null;
m_valueTs = 0;
m_bytesTs = 0;
m_bidiStringType = BidiStringType.DEFAULT; // @C6A
}
// Constructor
PcmlDataValues(PcmlData creator, PcmlDimensions indices)
{
this();
m_owner = creator;
m_indices = new PcmlDimensions(indices);
}
// Custom serialization
private void writeObject(ObjectOutputStream out) throws IOException // @C1A
{ // @C1A
synchronized (this) // @C1A
{ // @C1A
// For input values, serialize only the IBM i byte value
// if it is current than the Java value
if ( m_owner.getUsage() == PcmlDocNode.INPUT ) // @C1A
{ // @C1A
// If the byte value is more recent than the Java value
// convert the bytes to a Java value
if (m_bytesTs > m_valueTs) // @C1A
{ // @C1A
m_value = null; // @C1A
m_valueTs = 0; // @C1A
} // @C1A
} // @C1A
// For ouput values, serialize only the Java value
// if it is current than the IBM i byte value
if ( m_owner.getUsage() == PcmlDocNode.OUTPUT ) // @C1A
{
// If the byte value is more recent than the Java value
// convert the bytes to a Java value
if (m_valueTs > m_bytesTs) // @C1A
{ // @C1A
m_bytes = null; // @C1A
m_bytesTs = 0; // @C1A
} // @C1A
} // @C1A
// Perform default serialization
out.defaultWriteObject(); // @C1A
} // end of synchronized code // @C1A
} // @C1A
// Custom deserialization
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException // @C1A
{ // @C1A
// Default deserialization
in.defaultReadObject(); // @C1A
} // @C1A
// Custom deserialization post-processing
// This processing cannot be done during readObject() because
// references to parent objects in the document are not yet set
// due to the recursive nature of deserialization.
void readObjectPostprocessing() // @C1A
{ // @C1A
if (m_valueTs == m_bytesTs && m_valueTs > 0) // @C1A
{ // @C1A
m_valueTs = m_owner.getDoc().getDeserializationTimestamp(); // @C1A
m_bytesTs = m_owner.getDoc().getDeserializationTimestamp(); // @C1A
} // @C1A
if (m_valueTs > m_bytesTs) // @C1A
{ // @C1A
m_valueTs = m_owner.getDoc().getDeserializationTimestamp(); // @C1A
m_bytesTs = 0; // @C1A
} // @C1A
if (m_bytesTs > m_valueTs) // @C1A
{ // @C1A
m_bytesTs = m_owner.getDoc().getDeserializationTimestamp(); // @C1A
m_valueTs = 0; // @C1A
} // @C1A
} // @C1A
// Flush data values
// This allows the object to be reused when the
// m_owner (PcmlData object) redimensions its vectors.
void flushValues()
{
m_value = null;
m_bytes = null;
m_valueTs = 0;
m_bytesTs = 0;
}
// Get qualified name of data object
String getQualifiedName()
{
return m_owner.getQualifiedName();
}
// Get name for exceptions
String getNameForException()
{
return m_owner.getNameForException();
}
// Get Timestamp of data
long getTimestamp()
{
return Math.max(m_valueTs, m_bytesTs);
}
// Get Java native value
public Object getValue() throws PcmlException
{
return bytesToValue();
}
// Set Java native value
public void setValue(Object v) throws PcmlException
{
// Do not allow a null value to be set
if (v == null)
throw new PcmlException(DAMRI.NULL_VALUE, new Object[] {getNameForException()} );
// If the new value matches the Java type for this element
// store the new value.
if (getDataType() == PcmlData.STRUCT) { // @D0A
throw new PcmlException(DAMRI.STRUCT_VALUE, new Object[] {getNameForException()} ); // @D0A
}
if ( v.getClass().equals(getValueClass()) )
{
if (v instanceof BigDecimal) {
m_value = ((BigDecimal)v).setScale(getPrecision(), BigDecimal.ROUND_HALF_EVEN); // @D0A
}
else {
m_value = v;
}
}
// New value does not match the Java type for this element.
// Convert to the Java type needed -- errors may occur.
else
{
// Determine the timezone
TimeZone timeZone = m_owner.getDoc().getTimeZone();
m_value = convertValue(v, getDataType(), getLength(), getPrecision(), getNameForException(), timeZone);
}
// Update the value timestamp
m_valueTs = m_owner.getDoc().getCorrelationID();
}
// Set IBM i bytes
public void setBytes(byte[] ba)
{
m_bytes = ba;
m_bytesTs = m_owner.getDoc().getCorrelationID(); // @C7C
}
// Set the bidi string type
public void setStringType(int type) // @C6A
{
if (m_bidiStringType == type) // @C6A
{
// If new type is same as old, just return
return; // @C6A
}
// If we are setting a new string type, we want to
// clear the java value and timestamp. This will ensure
// that the correct conversion occurs on subsequent
// getValue() calls
m_bidiStringType = type; // @C6A
m_value = null; // @C6A
m_valueTs = 0; // @C6A
}
// Convert IBM i bytes to Java native value
private Object bytesToValue() throws PcmlException
{
// If the byte value is more recent than the Java value
// convert the bytes to a Java value
if (m_bytesTs > m_valueTs)
{
m_valueTs = m_bytesTs; // Update value timestamp
toObject(m_bytes);
}
// If value is not set and there is an
// init= value specified, initialize the value
if (m_value == null)
{
String initValue = m_owner.getInit();
if (initValue != null)
setValue(initValue);
}
if (m_value == null) // If value has not been set @C5A
return m_value; // return null @C5A
// Return the Java value
if (getDataType() == PcmlData.BYTE)
{
// Make a copy of the byte array, so caller can
// modify the value without repercussions
byte[] srcArray = (byte[]) m_value;
byte[] cloneArray = new byte[srcArray.length];
for (int b = 0; b element
if (tmpCcsid == 0)
{ // @C2A
PcmlNode node = m_owner.getParent(); // @C2A
node = node.getParent(); // get next ancestor @C7A
while (node != m_owner.getDoc()) // @C2A @C7C
node = node.getParent(); // @C2A
// If this element is a descendent of a Program element
// use the CCSID saved the last time the
if (node instanceof PcmlProgram) // @C2A
return ((PcmlProgram) node).getProgramCCSID(); // @C2A
else if (node instanceof RfmlDocument) // @D0A
return ((RfmlDocument) node).getCcsidInt(); // @D0A
else // @C2A
return m_owner.getDoc().getAs400().getCcsid(); // @C2A
} // @C2A
else
return tmpCcsid;
}
// Returns the precision= attribute
// The precision is only meaningful when type=int or packed
// For type=int:
// A 2-byte signed integer is: length=2 precision=15
// A 2-byte unsigned integer is: length=2 precision=16
// A 4-byte signed integer is: length=4 precision=31
// A 4-byte unsigned integer is: length=4 precision=32
// For type=packed:
// length= species the total number of digits
// precision= specifies the number of decimal digits
int getPrecision()
{
return m_owner.getPrecision();
}
// Returns the dateformat= attribute
// The dateformat is only meaningful when type=date
String getDateFormat()
{
return m_owner.getDateFormat();
}
// Returns the dateseparator= attribute
// The dateseparator is only meaningful when type=date
String getDateSeparator()
{
return m_owner.getDateSeparator();
}
// Returns the timeformat= attribute
// The timeformat is only meaningful when type=time
String getTimeFormat()
{
return m_owner.getTimeFormat();
}
// Returns the timeseparator= attribute
// The timeseparator is only meaningful when type=time
String getTimeSeparator()
{
return m_owner.getTimeSeparator();
}
String getTrim() // @D1A
{ // @D1A
return m_owner.getTrim(); // @D1A
} // @D1A
boolean isArray()
{
return m_owner.isArray();
}
// Return number of bytes required to perform toBytes();
// This is similar to C++ DataObject::FlattenedLengthAt()
public int byteLength() throws PcmlException
{
int length = getLength();
switch (getDataType())
{
case PcmlData.CHAR:
case PcmlData.INT:
case PcmlData.FLOAT:
case PcmlData.BYTE:
return length;
case PcmlData.PACKED:
return length / 2 + 1; // Packed contains 2 digits per byte plus sign
case PcmlData.ZONED:
return length; // Zoned contains 1 digit per byte, sign is in low order digit
case PcmlData.DATE:
if (length == 0) {
String format = getDateFormat();
if (format != null) {
length = AS400Date.getByteLength(AS400Date.toFormat(format), PcmlNode.separatorAsChar(getDateSeparator()));
}
}
return length;
case PcmlData.TIME:
if (length == 0) {
String format = getTimeFormat();
if (format != null) {
length = AS400Time.getByteLength(AS400Time.toFormat(format), PcmlNode.separatorAsChar(getTimeSeparator()));
}
}
return length;
case PcmlData.TIMESTAMP:
if (length == 0) {
//length = AS400Timestamp.getByteLength(null);
length = 26; // we publicly support only the 26-byte timestamp format
}
return length;
default:
throw new PcmlException(DAMRI.BAD_DATA_TYPE, new Object[] {new Integer(getDataType()) , getNameForException()} );
}
}
// Converts an object to the correct type (class) for
// the defined data tpe.
// The setValue method allows most data types to be set using
// either the Java class associaed with the data type or using
// a String. This method converts the value to the Java class
// defined for the data type. Exceptions such as
// NumberFormatException may result.
private Class getValueClass() throws PcmlException
{
int dataLength = getLength();
int dataPrecision = getPrecision();
int dataType = getDataType();
//try //@O6D
{
switch (dataType)
{
case PcmlData.CHAR:
return java.lang.String.class;// @O6C Class.forName("java.lang.String");
case PcmlData.INT:
if (dataLength == 2)
{
if (dataPrecision == 16)
{
return java.lang.Integer.class; //@O6C Class.forName("java.lang.Integer");
}
else
{ // dataPrecision == 15 or defaulted
return java.lang.Short.class; //@O6C Class.forName("java.lang.Short");
}
}
else
if (dataLength == 4) // @C3A
{ // dataLength == 4
if (dataPrecision == 32)
{
return java.lang.Long.class;//@O6C Class.forName("java.lang.Long");
}
else
{ // dataPrecision == 31 or defaulted
return java.lang.Integer.class;//@O6C Class.forName("java.lang.Integer");
}
}
else // @C3A
if (dataLength == 8) // @C3A
{ // dataLength == 8 // @C3A
if (dataPrecision == 64)
{
return java.math.BigInteger.class;//@O6C Class.forName("java.math.BigInteger");
}
else
{ // dataPrecision == 63 or defaulted
return java.lang.Long.class;//@O6C Class.forName("java.lang.Long"); // @C3A
}
} // @C3A
case PcmlData.PACKED:
case PcmlData.ZONED:
return java.math.BigDecimal.class;//@O6C Class.forName("java.math.BigDecimal");
case PcmlData.FLOAT:
if (dataLength == 4)
{
return java.lang.Float.class;//@O6C Class.forName("java.lang.Float");
}
else
{ // Must be length=8
return java.lang.Double.class;//@O6C Class.forName("java.lang.Double");
}
case PcmlData.BYTE:
return (new byte[0]).getClass();
case PcmlData.DATE:
return java.sql.Date.class;//@O6C Class.forName("java.sql.Date");
case PcmlData.TIME:
return java.sql.Time.class;//@O6C Class.forName("java.sql.Time");
case PcmlData.TIMESTAMP:
return java.sql.Timestamp.class;//@O6C Class.forName("java.sql.Timestamp");
default:
throw new PcmlException(DAMRI.BAD_DATA_TYPE, new Object[] {new Integer(getDataType()) , getNameForException()} );
} // END: switch (getDataType())
}
/* catch (ClassNotFoundException e) //@O6D
{
throw new PcmlException(DAMRI.CLASS_NOT_FOUND, new Object[] {new Integer(getDataType()) , getNameForException()} );
}*/
}
// Convert Java object IBM i bytes
// Returns the number of bytes converted
public int toBytes(OutputStream bytes, int offset) throws PcmlException
{
Object value = null;
int dataType = getDataType();
int dataLength = getLength();
if (dataLength == 0) { // this can happen with date, time, timestamp
dataLength = byteLength();
}
int bytesConverted = 0; // @B2A
// Get the Java object and make sure it has been set.
value = getValue();
if (value == null)
{
throw new PcmlException(DAMRI.INPUT_VALUE_NOT_SET, new Object[] {getNameForException()} );
}
// Get a converter from the PcmlDocument node.
// PcmlDocument will either create a converter or return an existing one.
AS400DataType converter = m_owner.getDoc().getConverter(dataType, dataLength, getPrecision(), getCcsid(), getDateFormat(), getDateSeparator(), getTimeFormat(), getTimeSeparator());
byte[] byteArray = new byte[dataLength];
if (dataType != PcmlData.CHAR) // @C6A
{
synchronized(converter) // @B1A
{ // @B1A
converter.toBytes(value, byteArray);
bytesConverted = converter.getByteLength(); // @B2A
} // @B1A
}
else // We need to use the string type for the conversion @C6A
{
synchronized(converter) // @C6A
{
((AS400Text)converter).toBytes(value, byteArray, 0, m_bidiStringType); // @C6A
bytesConverted = converter.getByteLength(); // @C6A
}
}
try { bytes.write(byteArray, 0, bytesConverted); }
catch (IOException e) { throw new PcmlException(e); }
// Detail tracing of data conversion
if (Trace.isTracePCMLOn()) // @D3C
{ // @B2A
String parseMsg; // @B2A
if (m_indices.size() > 0) // @B2A
{ // @B2A
parseMsg = SystemResourceFinder.format(DAMRI.WRITE_DATA_W_INDICES, new Object[] {Integer.toHexString(offset), Integer.toString(bytesConverted), getNameForException(), m_indices.toString(), PcmlMessageLog.toHexString(byteArray, 0, bytesConverted)} ); // @B2A
} // @B2A
else // @B2A
{ // @B2A
parseMsg = SystemResourceFinder.format(DAMRI.WRITE_DATA, new Object[] {Integer.toHexString(offset), Integer.toString(bytesConverted), getNameForException(), PcmlMessageLog.toHexString(byteArray, 0, bytesConverted)} ); // @B2A
} // @B2A
parseMsg = parseMsg + "\t " + Thread.currentThread(); // @B2A
Trace.log(Trace.PCML, parseMsg); // @D3C
} // @B2A
return bytesConverted; // @B2A
} // public int toBytes(OutputStream bytes, int offset)
// Convert IBM i bytes to Java Object
// Returns the Java Object
public Object toObject(byte[] bytes) throws PcmlException
{
Object newVal = null;
int dataType = getDataType();
// Get a converter from the PcmlDocument node.
// PcmlDocument will either create a converter or return an existing one.
AS400DataType converter = m_owner.getDoc().getConverter(dataType, getLength(), getPrecision(), getCcsid(), getDateFormat(), getDateSeparator(), getTimeFormat(), getTimeSeparator());
if (dataType != PcmlData.CHAR) // @C6A
{
synchronized(converter) // @B1A
{ // @B1A
newVal = converter.toObject(bytes);
} // @B1A
}
else // We need to use the string type for the conversion @C6A
{
synchronized(converter) // @C6A
{
newVal = ((AS400Text)converter).toObject(bytes, 0, m_bidiStringType); // @C6A
}
}
// For Strings, trim blanks and nulls appropriately
if (dataType == PcmlData.CHAR)
{
newVal = trimString((String) newVal, getTrim()); // @B2A @D1C
}
// Set the new value
setValue(newVal);
return newVal;
} // public int toBytes(byte[] bytes, int offset)
// Parses array of bytes and stores for later conversion
// to Java objects. This allows for lazy data translation
// for performance.
// Returns the number of bytes consumed from the input byte array
// Note: This may be larger than the number of bytes saved for this element
// because of bytes skipped due to an offset value.
public int parseBytes(byte[] bytes, int offset, Hashtable offsetStack) throws PcmlException
{
int nbrBytes = 0;
int skipBytes = 0;
// Adjust offset if necessary
// This is driven by the offset= attribute on the tag
int myOffset = getOffset();
if (myOffset != 0)
{
// Handle errors caused by bad offset values
if (myOffset < 0 || myOffset > bytes.length)
{
throw new PcmlException(DAMRI.BAD_OFFSET_VALUE, new Object[] {new Integer(myOffset), new Integer(bytes.length), "", getNameForException()} );
}
// Determine from where the offset is based
Integer myOffsetbase = null;
String myOffsetfrom = m_owner.getOffsetfromId(); // Get offsetfrom= element name, if any @A1C
// If offsetfrom= was specified with the name of another element,
// get the base for the offset from the offset stack.
// The offset stack is a stack of beginning offsets for all
// ancestors of the current element. The offsetfrom= value must be one
// of these ancestors or an error will be reported.
if (myOffsetfrom != null)
{
myOffsetbase = (Integer) offsetStack.get(myOffsetfrom);
if (myOffsetbase == null)
{
throw new PcmlException(DAMRI.OFFSETFROM_NOT_FOUND, new Object[] {myOffsetfrom, getNameForException()} );
}
}
else
{
// If offsetfrom= was specified with an integer literal, use it.
if (m_owner.getOffsetfrom() >= 0) // @A1A
{ // @A1A
myOffsetbase = new Integer(m_owner.getOffsetfrom()); // @A1A
} // @A1A
// getOffsetfrom() returns -1 to indicate that offset from was not specified.
// No offsetfrom= was specified, the offset will be relative to the
// beginning offset of the parent of this elements parent.
// This is the first (most recent) entry in the offset stack.
else // @A1A
{ // @A1A
myOffsetfrom = ((PcmlDocNode) m_owner.getParent()).getQualifiedName();
myOffsetbase = (Integer) offsetStack.get( myOffsetfrom );
} // @A1A
}
if (myOffsetbase != null)
{
myOffset = myOffset + myOffsetbase.intValue();
// Handle errors caused by bad offset values
if (myOffset < 0 || myOffset > bytes.length)
{
throw new PcmlException(DAMRI.BAD_TOTAL_OFFSET, new Object[] {new Integer(myOffset), new Integer(bytes.length), myOffsetbase, myOffsetfrom, "", getNameForException()} );
}
}
// If offset for this element is beyond current offset
// calculate number of bytes to skip
if (myOffset > offset)
{
skipBytes = myOffset - offset;
}
}
// Get number of bytes to parse for this value
nbrBytes = byteLength();
// Make sure length makes sense
if (nbrBytes < 0 || nbrBytes > PcmlData.MAX_STRING_LENGTH)
{
throw new PcmlException(DAMRI.BAD_DATA_LENGTH, new Object[] {new Integer(nbrBytes), new Integer(PcmlData.MAX_STRING_LENGTH), "", getNameForException()} ); // @C4C
}
// Make sure we are not trying to access more bytes than available.
if (offset + skipBytes + nbrBytes > bytes.length)
{
throw new PcmlException(DAMRI.INSUFFICIENT_INPUT_DATA, new Object[] {Integer.toString(offset + skipBytes + nbrBytes), Integer.toString(bytes.length), "", getNameForException()} );
}
// Finally, make a new byte array, copy the bytes, and save them
byte [] newBytes = new byte[nbrBytes];
for (int b = 0; b < nbrBytes; b++)
{
newBytes[b] = bytes[offset+ skipBytes + b];
}
setBytes(newBytes);
// Detail tracing of data parsing
if (Trace.isTracePCMLOn()) // @D3C
{
String parseMsg;
if (m_indices.size() > 0)
{
parseMsg = SystemResourceFinder.format(DAMRI.READ_DATA_W_INDICES, new Object[] {Integer.toHexString(offset+ skipBytes), Integer.toString(nbrBytes), getNameForException(), m_indices.toString(), PcmlMessageLog.toHexString(newBytes)} );
}
else
{
parseMsg = SystemResourceFinder.format(DAMRI.READ_DATA, new Object[] {Integer.toHexString(offset+ skipBytes), Integer.toString(nbrBytes), getNameForException(), PcmlMessageLog.toHexString(newBytes)} );
}
parseMsg = parseMsg + "\t " + Thread.currentThread();
Trace.log(Trace.PCML, parseMsg);
}
return skipBytes + nbrBytes;
} // End parseBytes()
// Resolve an integer value from either a named element or a literal
private int resolveIntegerValue(int intLiteral, String intId) throws PcmlException
{
PcmlData intNode;
Object nodeValue;
if (intId != null)
{
intNode = (PcmlData) ((PcmlDocRoot)m_owner.getRootNode()).getElement(intId);
nodeValue = intNode.getValue(m_indices);
if (nodeValue instanceof String)
{
return Integer.parseInt((String) nodeValue);
}
else if (nodeValue instanceof Number)
{
return ((Number) nodeValue).intValue();
}
else if (nodeValue == null)
{
throw new PcmlException(DAMRI.INPUT_VALUE_NOT_SET, new Object[] {intNode.getNameForException()} );
}
else
{
throw new PcmlException(DAMRI.STRING_OR_NUMBER, new Object[] {nodeValue.getClass().getName(), intNode.getNameForException()} );
}
}
return intLiteral;
}
// Converts an object to the correct type (class) for
// the defined data type.
// The setValue method allows most data types to be set using
// either the Java class associated with the data type or using
// a String. This method converts the value to the Java class
// defined for the data type. Exceptions such as
// NumberFormatException may result.
//
// This is implemented as a static method so it can be used
// to verify the init= attribute after parsing the pcml document tags.
public static Object convertValue(Object newVal, int dataType, int dataLength, int dataPrecision, String nodeNameForException, TimeZone serverTimeZone) throws PcmlException
{
Object convertedVal = null;
if (newVal == null)
throw new PcmlException(DAMRI.NULL_VALUE, new Object[] {nodeNameForException} );
switch (dataType)
{
case PcmlData.CHAR:
if (newVal instanceof String)
{
convertedVal = newVal;
}
else
{
convertedVal = newVal.toString();
}
break;
case PcmlData.INT:
if (dataLength == 2)
{
if (dataPrecision == 16)
{
if (newVal instanceof String)
{
convertedVal = new Integer((String) newVal);
}
else
{
if (newVal instanceof Integer)
{
convertedVal = newVal;
}
else if (newVal instanceof Number)
{
convertedVal = new Integer( ((Number) newVal).intValue() );
}
else
{
throw new PcmlException(DAMRI.STRING_OR_NUMBER, new Object[] {newVal.getClass().getName(), nodeNameForException} );
}
}
}
else
{ // dataPrecision == 15 or defaulted
if (newVal instanceof String)
{
convertedVal = new Short( ((String) newVal) );
}
else
{
if (newVal instanceof Short)
{
convertedVal = newVal;
}
else if (newVal instanceof Number)
{
convertedVal = new Short( ((Number) newVal).shortValue() );
}
else
{
throw new PcmlException(DAMRI.STRING_OR_NUMBER, new Object[] {newVal.getClass().getName(), nodeNameForException} );
}
}
}
}
else if (dataLength == 4) // @C3A
{
if (dataPrecision == 32)
{
if (newVal instanceof String)
{
convertedVal = new Long((String) newVal);
}
else
{
if (newVal instanceof Long)
{
convertedVal = newVal;
}
else if (newVal instanceof Number)
{
convertedVal = new Long( ((Number) newVal).longValue() );
}
else
{
throw new PcmlException(DAMRI.STRING_OR_NUMBER, new Object[] {newVal.getClass().getName(), nodeNameForException} );
}
}
}
else
{ // dataPrecision == 31 or defaulted
if (newVal instanceof String)
{
convertedVal = new Integer((String) newVal);
}
else
{
if (newVal instanceof Integer)
{
convertedVal = newVal;
}
else if (newVal instanceof Number)
{
convertedVal = new Integer( ((Number) newVal).intValue() );
}
else
{
throw new PcmlException(DAMRI.STRING_OR_NUMBER, new Object[] {newVal.getClass().getName(), nodeNameForException} );
}
}
}
}
else // @C3A
{ // dataLength == 8 // @C3A
if (dataPrecision == 64)
{
if (newVal instanceof String)
{
convertedVal = new BigInteger((String) newVal);
}
else
{
if (newVal instanceof BigInteger)
{
convertedVal = newVal;
}
else if (newVal instanceof Number)
{
long longVal = ((Number) newVal).longValue();
convertedVal = new BigInteger(Long.toString(longVal));
}
else
{
throw new PcmlException(DAMRI.STRING_OR_NUMBER, new Object[] {newVal.getClass().getName(), nodeNameForException} );
}
}
}
else
{ // dataPrecision == 63 or defaulted
if (newVal instanceof String) // @C3A
{ // @C3A
convertedVal = new Long((String) newVal); // @C3A
} // @C3A
else // @C3A
{ // @C3A
if (newVal instanceof Long)
{
convertedVal = newVal;
}
else if (newVal instanceof Number) // @C3A
{ // @C3A
convertedVal = new Long( ((Number) newVal).longValue() ); // @C3A
} // @C3A
else // @C3A
{ // @C3A
throw new PcmlException(DAMRI.STRING_OR_NUMBER, new Object[] {newVal.getClass().getName(), nodeNameForException} ); // @C3A
} // @C3A
} // @C3A
}
} // @C3A
break;
// Allows input value to be one of: BigDecimal, String or a subclass of Number
case PcmlData.PACKED:
case PcmlData.ZONED:
if (newVal instanceof BigDecimal)
{
convertedVal = ((BigDecimal)newVal).setScale(dataPrecision, BigDecimal.ROUND_HALF_EVEN); // @D0C
}
else
{
if (newVal instanceof String)
{
convertedVal = (new BigDecimal((String) newVal));
if (((BigDecimal)convertedVal).scale() != dataPrecision) {
convertedVal = ((BigDecimal)convertedVal).setScale(dataPrecision, BigDecimal.ROUND_HALF_EVEN); // @D0A
}
}
else
{
if (newVal instanceof Number)
{
convertedVal = (new BigDecimal(((Number) newVal).doubleValue())).setScale(dataPrecision, BigDecimal.ROUND_HALF_EVEN); // @D0C
}
else
{
throw new PcmlException(DAMRI.STRING_OR_NUMBER, new Object[] {newVal.getClass().getName(), nodeNameForException} );
}
}
}
break;
case PcmlData.FLOAT:
if (dataLength == 4)
{
if (newVal instanceof String)
{
convertedVal = new Float((String) newVal);
}
else
{
if (newVal instanceof Float)
{
convertedVal = newVal;
}
else if (newVal instanceof Number)
{
convertedVal = new Float( ((Number) newVal).floatValue() );
}
else
{
throw new PcmlException(DAMRI.STRING_OR_NUMBER, new Object[] {newVal.getClass().getName(), nodeNameForException} );
}
}
}
else
{ // Must be length=8
if (newVal instanceof String)
{
convertedVal = new Double((String) newVal);
}
else
{
if (newVal instanceof Double)
{
convertedVal = newVal;
}
else if (newVal instanceof Number)
{
convertedVal = new Double( ((Number) newVal).doubleValue() );
}
else
{
throw new PcmlException(DAMRI.STRING_OR_NUMBER, new Object[] {newVal.getClass().getName(), nodeNameForException} );
}
}
}
break;
case PcmlData.BYTE:
if (newVal instanceof String)
{
StringTokenizer st = new StringTokenizer((String) newVal, " ,");
byte byteVal = 0;
byte[] byteArray = new byte[dataLength];
for (int i=0; i < dataLength; i++)
{
if (st.hasMoreTokens())
{
String token = st.nextToken();
try {
byteVal = Byte.decode(token).byteValue();
}
catch (NumberFormatException nfe)
{
// If leftmost bit is on (as in, for example, 0x80), and token isn't prefixed by a minus sign, Byte.decode() throws a NumberFormatException.
// For such cases we must use a more accommodating conversion utility.
try {
byte[] bytes = BinaryConverter.stringToBytes(token);
byteVal = bytes[0];
}
catch (NumberFormatException e) {
// Rethrow original exception; it's more informative.
throw nfe;
}
}
}
else {
// Pad with final token in string
}
byteArray[i] = byteVal;
}
convertedVal = byteArray;
}
else
if (newVal instanceof Number)
{
byte byteVal = ((Number) newVal).byteValue();
byte[] byteArray = new byte[dataLength];
for (int i=0; i < dataLength; i++)
{
byteArray[i] = byteVal;
}
convertedVal = byteArray;
}
else
{
throw new PcmlException(DAMRI.STRING_OR_NUMBER, new Object[] {newVal.getClass().getName(), nodeNameForException} );
}
break;
case PcmlData.DATE:
if (newVal instanceof String)
{
// Parse XML Schema-style date value: yyyy-mm-dd
convertedVal = AS400Date.parseXsdString((String)newVal, serverTimeZone);
}
else
{
if (newVal instanceof java.sql.Date)
{
convertedVal = (java.sql.Date)newVal;
}
else
{
throw new PcmlException(DAMRI.STRING_OR_NUMBER, new Object[] {newVal.getClass().getName(), nodeNameForException} );
}
}
break;
case PcmlData.TIME:
if (newVal instanceof String)
{
// Parse XML Schema-style time value: hh:mm:ss
convertedVal = AS400Time.parseXsdString((String)newVal, serverTimeZone);
}
else
{
if (newVal instanceof java.sql.Time)
{
convertedVal = (java.sql.Time)newVal;
}
else
{
throw new PcmlException(DAMRI.STRING_OR_NUMBER, new Object[] {newVal.getClass().getName(), nodeNameForException} );
}
}
break;
case PcmlData.TIMESTAMP:
if (newVal instanceof String)
{
// Parse XML Schema-style timestamp value: yyyy-MM-ddTHH:mm:ss.SSSSSSSSS
convertedVal = AS400Timestamp.parseXsdString((String)newVal, serverTimeZone);
}
else
{
if (newVal instanceof java.sql.Timestamp)
{
convertedVal = (java.sql.Timestamp)newVal;
}
else
{
throw new PcmlException(DAMRI.STRING_OR_NUMBER, new Object[] {newVal.getClass().getName(), nodeNameForException} );
}
}
break;
default:
throw new PcmlException(DAMRI.BAD_DATA_TYPE, new Object[] {new Integer(dataType) , nodeNameForException} );
} // END: switch (getDataType())
return convertedVal;
}
// Trims blanks and nulls from the ends of a string
// Returns the trimmed string // @D1C
static String trimString(String str, String trimEnd)
{
if (trimEnd != null && trimEnd.equals("none"))
{
return str;
}
char[] charBuff = str.toCharArray();
int startOffset = 0; // Used when constructing return string
int lengthReturned = charBuff.length; // Used when constructing return string
if (trimEnd == null || trimEnd.equals("right") || trimEnd.equals("both") )
{
// Trim blanks and nulls
trimRight: while (lengthReturned > 0)
{
switch (charBuff[lengthReturned-1])
{
case ' ':
case '\0':
lengthReturned--;
break;
default:
break trimRight;
}
}
}
if (trimEnd != null && (trimEnd.equals("left") || trimEnd.equals("both")) )
{
// Trim blanks and nulls
trimLeft: while (startOffset < lengthReturned)
{
switch (charBuff[startOffset])
{
case ' ':
case '\0':
startOffset++;
lengthReturned--;
break;
default:
break trimLeft;
}
}
}
return new String(charBuff, startOffset, lengthReturned);
}
}