/*
* (C) Copyright IBM Corp. 2010
*
* LICENSE: Eclipse Public License v1.0
* http://www.eclipse.org/legal/epl-v10.html
*/
package com.ibm.gaiandb.udpdriver.common.protocol;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.InetAddress;
import java.util.ArrayList;
/**
* MetaData protocol message.
* In addition to meta data information, MetaData could contain serialized database records.
*
* The binary format is :
* |messageHeader|numberOfParameters|numberOfColumns|columnTypes|numberOfNullableColumns|nullableColumns|columnNames|columnScale|columnPrecision|columnDisplaySize|containDatabaseRecords|
*
* if containDatabaseRecords==true, then there is |responseWithValuesBinaryFormat| at the end.
*
* @author lengelle
*
*/
public class MetaData extends ResponseWithValues
{
// Use PROPRIETARY notice if class contains a main() method, otherwise use COPYRIGHT notice.
public static final String COPYRIGHT_NOTICE = "(c) Copyright IBM Corp. 2010";
ByteArrayOutputStream baos ;
DataOutputStream daos ;
boolean metaDataHeaderSerializationDone;
private int numberOfParameters;
private int numberOfColumns;
private int numberOfNullableColumns;
private int[] columnTypeTab;
private int[] columnScale;
private int[] columnDisplaySize;
private int[] columnPrecision;
private ArrayList<Integer> nullableColumnList;
private String[] columnNameTab;
/**
* Creates a new MetaData
*/
public MetaData()
{
super();
numberOfParameters = -1;
numberOfColumns = -1;
columnTypeTab = null;
numberOfNullableColumns = -1;
nullableColumnList = new ArrayList<Integer>( LIST_INITIAL_SIZE );
columnNameTab = null;
metaDataHeaderSerializationDone = false;
}
/* (non-Javadoc)
* @see com.ibm.gaiandb.udpdriver.common.protocol.ResponseWithValues#initializeWithData(byte[], java.net.InetAddress, int)
*/
public void initializeWithData( byte[] data, InetAddress emittingAdress, int emittingPort ) throws UDPProtocolException
{
super.initializeWithData( data, emittingAdress, emittingPort );
try
{
deserializeData();
}
catch( Exception e )
{
throw new UDPProtocolException( "MetaData - constructor failed.", e );
}
}
/* (non-Javadoc)
* @see com.ibm.gaiandb.udpdriver.common.protocol.ResponseWithValues#clean()
*/
public void clean()
{
super.clean();
numberOfParameters = -1;
numberOfColumns = -1;
columnTypeTab = null;
numberOfNullableColumns = -1;
nullableColumnList.clear();
columnNameTab = null;
columnScale = null;
columnDisplaySize = null;
columnPrecision = null;
metaDataHeaderSerializationDone = false;
baos = null;
daos = null;
}
/* (non-Javadoc)
* @see com.ibm.gaiandb.udpdriver.common.protocol.Message#deserializeData()
*/
protected void deserializeData() throws UDPProtocolException
{
try
{
ByteArrayInputStream bais = new ByteArrayInputStream( binaryData );
DataInputStream dis = new DataInputStream( bais );
dis.readByte(); // the message type
queryID = dis.readUTF();
sequenceNumber = dis.readInt();
numberOfParameters = dis.readInt();
numberOfColumns = dis.readInt();
columnTypeTab = new int[numberOfColumns];
for ( int i=0; i<numberOfColumns; ++i )
{
columnTypeTab[i] = dis.readInt();
}
numberOfNullableColumns = dis.readInt();
for ( int i=0; i<numberOfNullableColumns; ++i )
{
nullableColumnList.add( dis.readInt() );
}
columnNameTab = new String[numberOfColumns];
for ( int i=0; i<numberOfColumns; ++i )
{
columnNameTab[i] = dis.readUTF();
}
columnScale = new int[numberOfColumns];
for ( int i=0; i<numberOfColumns; ++i )
{
columnScale[i] = dis.readInt();
}
columnPrecision = new int[numberOfColumns];
for ( int i=0; i<numberOfColumns; ++i )
{
columnPrecision[i] = dis.readInt();
}
columnDisplaySize = new int[numberOfColumns];
for ( int i=0; i<numberOfColumns; ++i )
{
columnDisplaySize[i] = dis.readInt();
}
if ( dis.readBoolean() )
{
// There are serialized values in the message
deserializedValuesHelper( dis );
}
dis.close();
bais.close();
}
catch( Exception e )
{
throw new UDPProtocolException( "MetaData deserializeData() failed. ", e );
}
}
public int getType()
{
return Message.META_DATA;
}
public int getNumberOfColumns()
{
return numberOfColumns;
}
public int getNumberOfNullableColumns()
{
return numberOfNullableColumns;
}
public ArrayList<Integer> getNullableColumns()
{
return nullableColumnList;
}
public String[] getColumnNames()
{
return columnNameTab;
}
public int[] getColumnTypes()
{
return columnTypeTab;
}
public int getNumberOfParameters()
{
return numberOfParameters;
}
public void setNumberOfColumns( int numberOfColumns )
{
this.numberOfColumns = numberOfColumns;
}
public void setNumberOfParameters( int numberOfParameters )
{
this.numberOfParameters = numberOfParameters;
}
public void setNumberOfNullableColumns( int numberOfNullableColumns )
{
this.numberOfNullableColumns = numberOfNullableColumns;
}
public void addNullableColumnIndex( int nullableColumnIndex )
{
nullableColumnList.add( nullableColumnIndex );
}
public void setColumnTypes( int[] columnTypes )
{
this.columnTypeTab = columnTypes;
}
public void setColumnNames( String[] columnNames )
{
this.columnNameTab = columnNames;
}
public int[] getColumnScale()
{
return columnScale;
}
public void setColumnScale( int[] columnScale )
{
this.columnScale = columnScale;
}
public int[] getColumnDisplaySize()
{
return columnDisplaySize;
}
public void setColumnDisplaySize( int[] columnDisplaySize )
{
this.columnDisplaySize = columnDisplaySize;
}
public int[] getColumnPrecision()
{
return columnPrecision;
}
public void setColumnPrecision( int[] columnPrecision )
{
this.columnPrecision = columnPrecision;
}
/* (non-Javadoc)
* @see com.ibm.gaiandb.udpdriver.common.protocol.Message#serializeMessage()
*/
public byte[] serializeMessage() throws UDPProtocolException
{
try
{
serializeMetaDataHeader();
if ( numberOfRows > 0 )
{
daos.writeBoolean( true );
serializeValuesHelper( daos );
}
else
{
daos.writeBoolean( false );
}
daos.close();
byte[] serialized = baos.toByteArray();
baos.close();
return serialized;
}
catch( Exception e )
{
throw new UDPProtocolException( "MetaData - serializeMessage() failed. ", e );
}
}
/**
* Serialize only the meta data attributes into the stream.
*
* @throws UDPProtocolException
*/
private void serializeMetaDataHeader() throws UDPProtocolException
{
try
{
if ( !metaDataHeaderSerializationDone )
{
baos = new ByteArrayOutputStream( BYTE_ARRAY_INITIAL_SIZE );
daos = new DataOutputStream( baos );
if ( queryID==null || sequenceNumber==-1 )
{
throw new UDPProtocolException( "The fields 'queryID' or 'sequenceNumber' are not initialized. " );
}
daos.writeByte( getType() );
daos.writeUTF( queryID );
daos.writeInt( sequenceNumber );
if ( numberOfParameters < 0 )
{
throw new UDPProtocolException( "numberOfParameters field is not initilized." );
}
daos.writeInt( numberOfParameters );
if ( numberOfColumns <= 0 )
{
throw new UDPProtocolException( "numberOfColumns field is not initilized." );
}
daos.writeInt( numberOfColumns );
if ( columnTypeTab == null )
{
throw new UDPProtocolException( "columnTypeTab field is not initilized." );
}
for ( int i=0; i<numberOfColumns; ++i )
{
daos.writeInt( columnTypeTab[i] );
}
if ( numberOfNullableColumns < 0 )
{
throw new UDPProtocolException( "numberOfNullableColumns field is not initilized." );
}
daos.writeInt( numberOfNullableColumns );
if ( numberOfNullableColumns > 0 )
{
if ( nullableColumnList == null )
{
throw new UDPProtocolException( "nullableColumnList field is not initilized." );
}
for ( int i=0; i<numberOfNullableColumns; ++i )
{
daos.writeInt( nullableColumnList.get( i ) );
}
}
if ( columnNameTab == null )
{
throw new UDPProtocolException( "columnNameTab field is not initilized." );
}
for ( int i=0; i<numberOfColumns; ++i )
{
daos.writeUTF( columnNameTab[i] );
}
if ( columnScale == null )
{
throw new UDPProtocolException( "columnScale field is not initilized." );
}
for ( int i=0; i<numberOfColumns; ++i )
{
daos.writeInt( columnScale[i] );
}
if ( columnPrecision == null )
{
throw new UDPProtocolException( "columnPrecision field is not initilized." );
}
for ( int i=0; i<numberOfColumns; ++i )
{
daos.writeInt( columnPrecision[i] );
}
if ( columnDisplaySize == null )
{
throw new UDPProtocolException( "columnDisplaySize field is not initilized." );
}
for ( int i=0; i<numberOfColumns; ++i )
{
daos.writeInt( columnDisplaySize[i] );
}
metaDataHeaderSerializationDone = true;
}
}
catch( Exception e )
{
throw new UDPProtocolException( "MetaData - serializeMetaDataHeader() failed. ", e );
}
}
/* (non-Javadoc)
* @see com.ibm.gaiandb.udpdriver.common.protocol.ResponseWithValues#estimateHeaderSize()
*/
public int estimateHeaderSize() throws UDPProtocolException
{
try
{
serializeMetaDataHeader();
// metaData|boolean containsValues|ResponseWithValuesHeader
return baos.size() + 1 + estimateHeaderSizeHelper();
}
catch( Exception e )
{
throw new UDPProtocolException( "MetaData - estimateHeaderSize() failed.", e );
}
}
}