/* * (C) Copyright IBM Corp. 2010 * * LICENSE: Eclipse Public License v1.0 * http://www.eclipse.org/legal/epl-v10.html */ package com.ibm.gaiandb.udpdriver.client; import java.io.ByteArrayInputStream; import java.io.ObjectInput; import java.io.ObjectInputStream; import java.sql.Types; import java.util.List; import org.apache.derby.iapi.types.DataValueDescriptor; import com.ibm.gaiandb.udpdriver.common.RowsFilter; import com.ibm.gaiandb.udpdriver.common.protocol.MessageFactory; import com.ibm.gaiandb.udpdriver.common.protocol.ResponseWithValues; /** * This object deserialize database records received, in their binary format, from the UDP driver server. * Because the meta data are different for each queries, a instance of ValuesDecoder can be used only for a complete processing of one query. * * @author lengelle */ public class ValuesDecoder { // Use PROPRIETARY notice if class contains a main() method, otherwise use COPYRIGHT notice. public static final String COPYRIGHT_NOTICE = "(c) Copyright IBM Corp. 2010"; private UDPResultSetMetaData metaData; private boolean[] columnsWithChar; private ResponseWithValues response; // Deserialization fields private int coefficient; private int nullValuesIndex; private int numberOfRowRead; private int numberOfNullValues; private List<Integer> nullValues; private ByteArrayInputStream bais; private ObjectInput ois; /** * Instantiates a ValuesDecoder. * * @param metaData meta data associated with the query * @param response protocol message containing the serialized values * @throws UDPDriverClientException */ public ValuesDecoder( UDPResultSetMetaData metaData, ResponseWithValues response ) throws UDPDriverClientException { try { this.metaData = metaData; this.response = response; //Set a boolean array indicating CHAR, VARCHAR, LONGVARCHAR columns. columnsWithChar = new boolean[ this.metaData.getColumnCount() ]; int type; for ( int i=0; i<columnsWithChar.length; ++i ) { type = this.metaData.getColumnType( i+1 ); if ( type==Types.CHAR || type==Types.VARCHAR || type==Types.LONGVARCHAR ) { columnsWithChar[i] = true; } else { columnsWithChar[i] = false; } } initializeDeserializationFields(); } catch( Exception e ) { throw new UDPDriverClientException( "ValuesDecoder - constructor failed. ", e ); } } /** * Returns a DVD row from the message. * If the last records has already been deserialized, returns null. * * Takes in parameter a DVD array to recycle. If null, a new DVD array will be * instantiated. * * @param toRecycle * @return * @throws UDPDriverClientException */ public DataValueDescriptor[] decodeOneRow( DataValueDescriptor[] toRecycle ) throws UDPDriverClientException { try { if ( numberOfRowRead==response.getNumberOfRows() ) { return null; } DataValueDescriptor[] dvdr = null; if ( toRecycle==null ) { dvdr = createNewDVDRowFromMetaData( metaData ); } else { dvdr = toRecycle; } DataValueDescriptor dvdTemp = null; for( int i=0; i<dvdr.length; ++i ) { dvdTemp = dvdr[i]; if ( numberOfNullValues!=0 && nullValuesIndex<numberOfNullValues && nullValues.get( nullValuesIndex ).equals( i + coefficient ) ) { dvdTemp.setToNull(); ++nullValuesIndex; } else { dvdTemp.readExternal( ois ); //Due to derby serialization issue with empty string "". if ( columnsWithChar[i] && dvdTemp.getLength()==1 ) { if ( dvdTemp.getString().equals( "\0" ) ) { dvdTemp.setValue( "" ); } } } dvdr[i] = dvdTemp; } ++numberOfRowRead; coefficient = coefficient + dvdr.length; return dvdr; } catch( Exception e ) { throw new UDPDriverClientException( "ValuesDecoder - decodeOneRow() failed. ", e ); } } /** * Set a new protocol message containing serialized values. * This new message replaces the previous one. * * @param newResponseWithValues * @throws UDPDriverClientException */ public void setNewResponseWithValues( ResponseWithValues newResponseWithValues ) throws UDPDriverClientException { try { MessageFactory.returnMessage( response ); response = newResponseWithValues; initializeDeserializationFields(); } catch( Exception e ) { throw new UDPDriverClientException( "setNewResponseWithValues - closeStreams() failed. ", e ); } } private void closeStreams() throws UDPDriverClientException { try { if ( ois != null ) { ois.close(); ois = null; } if ( bais != null ) { bais.close(); bais = null; } } catch( Exception e ) { throw new UDPDriverClientException( "ValuesDecoder - closeStreams() failed. ", e ); } } private void initializeDeserializationFields() throws UDPDriverClientException { try { coefficient = 0; nullValuesIndex = 0; numberOfRowRead = 0; numberOfNullValues = response.getNumberOfNullValues(); nullValues = response.getNullValues(); closeStreams(); if ( response.getNumberOfRows()>0 && response.getBinaryValues()!=null ) { bais = new ByteArrayInputStream( response.getBinaryValues() ); ois = new ObjectInputStream( bais ); } } catch( Exception e ) { throw new UDPDriverClientException( "ValuesDecoder - initializeDeserializationFields() failed. ", e ); } } private DataValueDescriptor[] createNewDVDRowFromMetaData( UDPResultSetMetaData metaData ) throws UDPDriverClientException { try { DataValueDescriptor[] dvdr = null; int numberOfColumns = metaData.getColumnCount(); if ( numberOfColumns != 0 ) { dvdr = new DataValueDescriptor[ numberOfColumns ]; for ( int i=0; i<dvdr.length; ++i ) { dvdr[i] = RowsFilter.constructDVDMatchingJDBCType( metaData.getColumnType( i+1 ) ); } } return dvdr; } catch( Exception e ) { throw new UDPDriverClientException( "ValuesDecoder - createNewDVDRowFromMetaData() failed. ", e ); } } public boolean isDecodingLastShipement() { return response.containsLastValues(); } /** * Close the ValuesDecoder. * Once closed, the ValuesDecoder could not be used anymore. * * @throws UDPDriverClientException */ public void close() throws UDPDriverClientException { try { MessageFactory.returnMessage( response ); response = null; columnsWithChar = null; nullValues = null; closeStreams(); } catch( Exception e ) { throw new UDPDriverClientException( "ValuesDecoder - close() failed. ", e ); } } }