/* Copyright (c) 2005 Ricebridge. All Rights Reserved.
 *
 * This file is available under the terms and conditions of the
 * Ricebridge "Open Source API" policy; Ricebridge grants use of this
 * copyrighted work under the terms of a BSD-style license only. See
 * http://www.opensource.org/licenses/bsd-license.php for more
 * information.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 *  - Redistributions of source code must retain the above copyright
 *  notice, this list of conditions and the following disclaimer.
 *
 *  - Redistributions in binary form must reproduce the above
 *  copyright notice, this list of conditions and the following
 *  disclaimer in the documentation and/or other materials provided
 *  with the distribution.
 *
 *  - Neither the name of the Ricebridge nor the names of its
 *  contributors may be used to endorse or promote products derived
 *  from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.  
 */


package com.ricebridge.xmlman.in;


import org.jostraca.util.Internal;
import org.jostraca.util.TextUtil;

import java.sql.*;
import java.io.InputStream;
import java.io.Reader;
import java.net.URL;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.util.Map;
import java.util.Calendar;
import java.util.ArrayList;
import java.util.List;
import java.util.Iterator;


/** Implementation of a <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/sql/ResultSet.html">ResultSet</a> to present XML data.
 *    <p>This <code>ResultSet</code> provides much the same interface as a database <code>ResultSet</code>.
 *  This implementation assumes that your data is fairly well behaved and attempts direct data type
 *  conversions for methods like {@link #getInt}. Bad data will cause an exception to be thrown.
 *  Refer to {@link java.sql.ResultSet} for method documentation if none is given here.</p>
 *    <p>NOTE: in order to reuse the 
 *    <p>The <b><a href="XmlResultSet.java.html">Source Code</a></b> of this Java class 
 *    is available under a <a href="http://www.opensource.org/licenses/bsd-license.php">BSD-style license</a>.</p>
 */
public class XmlResultSet implements ResultSet {

  // not supported

  public Array      getArray(  String pColName ) throws SQLException { throw new UnsupportedOperationException(); }
  public Array      getArray(  int pIndex ) throws SQLException { throw new UnsupportedOperationException(); }
  public Blob       getBlob(   String pColName ) throws SQLException { throw new UnsupportedOperationException(); }
  public Blob       getBlob(   int pIndex ) throws SQLException { throw new UnsupportedOperationException(); }
  public Clob       getClob(   String pColName ) throws SQLException { throw new UnsupportedOperationException(); }
  public Clob       getClob(   int pIndex ) throws SQLException { throw new UnsupportedOperationException(); }
  public Object     getObject( String pColName, Map pMap ) throws SQLException { throw new UnsupportedOperationException(); }
  public Object     getObject( int pIndex, Map pMap ) throws SQLException { throw new UnsupportedOperationException(); }
  public Ref        getRef(    String pColName ) throws SQLException { throw new UnsupportedOperationException(); }
  public Ref        getRef(    int pIndex ) throws SQLException { throw new UnsupportedOperationException(); }
  public Statement  getStatement() throws SQLException { throw new UnsupportedOperationException(); }


  // no action
    
  public SQLWarning getWarnings() throws SQLException { return null; }
  public String     getCursorName() throws SQLException { return ""; }
  public boolean    rowDeleted( ) throws SQLException { return false; }
  public boolean    rowInserted( ) throws SQLException { return false; }
  public boolean    rowUpdated( ) throws SQLException { return false; }
  public boolean    wasNull( ) throws SQLException { return false; }
  public int        getFetchDirection( ) throws SQLException { return FETCH_FORWARD; }
  public void       setFetchDirection( int pDirection ) throws SQLException { }
  public int        getFetchSize( ) throws SQLException { return 0; }
  public void       setFetchSize( int pRows ) throws SQLException { }
  public int        getConcurrency( ) throws SQLException { return CONCUR_READ_ONLY; }
  public void       cancelRowUpdates( ) throws SQLException {}
  public void       clearWarnings( ) throws SQLException {}
  public void       close( ) throws SQLException {}
  public void       deleteRow( ) throws SQLException {}
  public void       insertRow( ) throws SQLException {}
  public void       moveToCurrentRow( ) throws SQLException {}
  public void       moveToInsertRow( ) throws SQLException {}
  public void       refreshRow( ) throws SQLException {}
  public void       updateArray( String pColumnName, Array pArray ) throws SQLException {}
  public void       updateArray( int pColumnIndex, Array pArray ) throws SQLException {}
  public void       updateAsciiStream( String pColumnName, InputStream pInputStream, int pLength ) throws SQLException {}
  public void       updateAsciiStream( int pColumnIndex, InputStream pInputStream,  int pLength ) throws SQLException {}
  public void       updateBigDecimal( String pColumnName, BigDecimal pBigDecimal ) throws SQLException {}
  public void       updateBigDecimal( int pColumnIndex, BigDecimal pBigDecimal ) throws SQLException {}
  public void       updateBinaryStream( String pColumnName, InputStream pInputStream, int pLength ) throws SQLException {}
  public void       updateBinaryStream( int pColumnIndex, InputStream pInputStream,  int pLength ) throws SQLException {}
  public void       updateBlob( String pColumnName, Blob pBlob ) throws SQLException {}
  public void       updateBlob( int pColumnIndex, Blob pBlob ) throws SQLException {}
  public void       updateBoolean( String pColumnName, boolean pValue ) throws SQLException {}
  public void       updateBoolean( int pColumnIndex, boolean pValue ) throws SQLException {}
  public void       updateByte( String pColumnName, byte pValue ) throws SQLException {}
  public void       updateByte( int pColumnIndex, byte pValue ) throws SQLException {}
  public void       updateBytes( String pColumnName, byte pBytes[] ) throws SQLException {}
  public void       updateBytes( int pColumnIndex, byte pBytes[] ) throws SQLException {}
  public void       updateCharacterStream( String pColumnName, Reader pReader, int pLength ) throws SQLException {}
  public void       updateCharacterStream( int pColumnIndex, Reader pReader, int pLength ) throws SQLException {}
  public void       updateClob( String pColumnName, Clob pValue ) throws SQLException {}
  public void       updateClob( int pColumnIndex, Clob pValue ) throws SQLException {}
  public void       updateDate( String pColumnName, Date pValue ) throws SQLException {}
  public void       updateDate( int pColumnIndex, Date pValue ) throws SQLException {}
  public void       updateDouble( String pColumnName, double pValue ) throws SQLException {}
  public void       updateDouble( int pColumnIndex, double pValue ) throws SQLException {}
  public void       updateFloat( String pColumnName, float pValue ) throws SQLException {}
  public void       updateFloat( int pColumnIndex, float pValue ) throws SQLException {}
  public void       updateInt( String pColumnName, int pValue ) throws SQLException {}
  public void       updateInt( int pColumnIndex, int pValue ) throws SQLException {}
  public void       updateLong( String pColumnName, long pValue ) throws SQLException {}
  public void       updateLong( int pColumnIndex, long pValue ) throws SQLException {}
  public void       updateNull( String pColumnName ) throws SQLException {}
  public void       updateNull( int pColumnIndex ) throws SQLException {}
  public void       updateObject( String pColumnName, Object pValue ) throws SQLException {}
  public void       updateObject( String pColumnName, Object pValue, int pScale )  throws SQLException {}
  public void       updateObject( int pColumnIndex, Object pValue ) throws SQLException {}
  public void       updateObject( int pColumnIndex, Object pValue, int pScale ) throws SQLException {}
  public void       updateRef( String pColumnName, Ref pValue ) throws SQLException {}
  public void       updateRef( int pColumnIndex, Ref pValue ) throws SQLException {}
  public void       updateRow( ) throws SQLException {}
  public void       updateShort( String pColumnName, short pValue ) throws SQLException {}
  public void       updateShort( int pColumnIndex, short pValue ) throws SQLException {}
  public void       updateString( String pColumnName, String pValue ) throws SQLException {}
  public void       updateString( int pColumnIndex, String pValue ) throws SQLException {}
  public void       updateTime( String pColumnName, Time pValue ) throws SQLException {}
  public void       updateTime( int pColumnIndex, Time pValue ) throws SQLException {}
  public void       updateTimestamp( String pColumnName, Timestamp pValue ) throws SQLException {}
  public void       updateTimestamp( int pColumnIndex, Timestamp pValue )  throws SQLException {}


  // supported

  /** Data as a <code>List</code> of <code>String[]</code> arrays. */
  protected ArrayList iData;

  /** Current data record. */
  protected String[] iRecord;

  /** index of current record. */
  protected long iRecordIndex;

  /** Default data format for date parsing. */
  protected DateFormat iDateFormat;

  /** ResultSetMetaData provider */
  protected XmlResultSetMetaData iXmlRSMD;

  /** The first line of the CSV file may contain headers. */
  protected boolean   iDataHasHeaders;

  /** Flag to indicate that headers have been loaded. */
  protected boolean   iHeadersStored;


  /** Support {@link java.lang.Class#newInstance} object instantiation. */
  public XmlResultSet() {
    init();
  }


  /** Create a new <code>ResultSet</code> with specified a <code>List</code> of <code>String[]</code> arrays. */
  public XmlResultSet( List pData ) {
    init();

    List data = Internal.null_list( pData );
    iData.addAll(data);

    String[] headers = null;
    if( 0 < iData.size() ) {
      String[] first = (String[])iData.get(0);
      int numh = first.length;
      headers = new String[numh];
      for( int hI = 0; hI < numh; hI++ ) {
        headers[hI] = "Column "+hI;
      }
    }
    else {
      headers = new String[]{};
    }

    iXmlRSMD = new XmlResultSetMetaData( headers );
  }


  /** Initialise the internal data containers before loading new XML record data. */
  public void init() {
    iData           = new ArrayList();
    iRecord         = null;
    iRecordIndex    = -1;
    iDateFormat     = DateFormat.getDateInstance();
    iXmlRSMD        = null;
    iDataHasHeaders = false;
    iHeadersStored  = false; 
  }


  /** The first record contains the column names. 
   *  @param pDataHasHeaders flag headers in data
   */
  public void setDataHasHeaders( boolean pDataHasHeaders ) {
    iDataHasHeaders = pDataHasHeaders;
  }


  /** Set the column header names.
   *  @param pHeaders field names are used as column header names
   */
  public void setHeaders( String[] pHeaders ) {
    iXmlRSMD = new XmlResultSetMetaData( pHeaders );
  }


  /** Set data for <code>ResultSet</code>.
   *  @param pRecord     data record
   */
  public void addRecord( String[] pRecord ) {
    if( iDataHasHeaders && !iHeadersStored ) {
      iXmlRSMD = new XmlResultSetMetaData( pRecord );
      iHeadersStored = true;
    }
    else {
      iData.add( pRecord );
    }
  }


  /** Get the number of rows. */
  public int getRowCount() {
    return iData.size();
  }


  /** Specify custom date format.
   *  @param pDateFormat custom data format
   */
  public void setDateFormat( DateFormat pDateFormat ) {
    iDateFormat = (DateFormat) Internal.null_arg( pDateFormat );
  }


  /** Remove all data rows. */
  public void clear() {
    iData.clear();
  }


  /** <code>String</code> description of object instance. */
  public String toString() {
    return "XmlResultSet[head:"+iDataHasHeaders+", data:"+makeString(iData)+"]";
  }



  // ResultSet methods

  public int getType() throws SQLException { 
    return TYPE_SCROLL_INSENSITIVE; 
  }


  public ResultSetMetaData getMetaData( ) throws SQLException {
    return iXmlRSMD;
  }


  public int findColumn( String pColumnName  ) throws SQLException {
    return iXmlRSMD.findColumn( pColumnName );
  }


  public boolean absolute( int pRow  ) throws SQLException {
    if( pRow > 0 ) {
      iRecordIndex = pRow - 1;
    }
    else {
      iRecordIndex = iData.size() + pRow;
    }
    return moveToLine();
  }

  public boolean first( ) throws SQLException {
    return absolute(1);
  }

  public boolean last( ) throws SQLException {
    return absolute(-1);
  }


  public boolean isAfterLast( ) throws SQLException {
    return iRecordIndex >= iData.size(); 
  }

  public boolean isBeforeFirst( ) throws SQLException {
    return iRecordIndex <= -1;
  }

  public boolean isFirst( ) throws SQLException {
    return 0 == iRecordIndex;
  }

  public boolean isLast( ) throws SQLException {
    return iData.size() - 1 == iRecordIndex;
  }


  public boolean next( ) throws SQLException {
    return relative(1);
  }

  public boolean previous( ) throws SQLException {
    return relative(-1);
  }

  public boolean relative( int pRows  ) throws SQLException {
    iRecordIndex += pRows;
    return moveToLine();
  }


  public int getRow( ) throws SQLException {
    return (int) iRecordIndex+1;
  }

  public void afterLast( ) throws SQLException {
    iRecordIndex = iData.size();
  }

  public void beforeFirst( ) throws SQLException {
    iRecordIndex = -1;
  }

  public BigDecimal getBigDecimal( String pColumnName  ) throws SQLException {
    return getBigDecimal( findColumn(pColumnName) );
  }

  public BigDecimal getBigDecimal( String pColumnName, int pScale  ) throws SQLException {
    return getBigDecimal( findColumn(pColumnName), pScale );
  }

  public BigDecimal getBigDecimal( int pColumnIndex  ) throws SQLException {
    return new BigDecimal( iRecord[pColumnIndex-1] );
  }
  
  public BigDecimal getBigDecimal( int pColumnIndex, int pScale  ) throws SQLException {
    return new BigDecimal( iRecord[pColumnIndex-1] ).setScale( pScale );
  }

  public Object getObject( String pColumnName  ) throws SQLException {
    return getObject(findColumn(pColumnName));
  }

  public Object getObject( int pColumnIndex  ) throws SQLException {
    return iRecord[pColumnIndex-1];
  }

  public String getString( String pColumnName  ) throws SQLException {
    return getString(findColumn(pColumnName));
  }

  public String getString( int pColumnIndex  ) throws SQLException {
    return iRecord[pColumnIndex-1];
  }

  public boolean getBoolean( String pColumnName  ) throws SQLException {
    return getBoolean( findColumn(pColumnName ) );
  }

  public boolean getBoolean( int pColumnIndex  ) throws SQLException {
    return new Boolean( iRecord[pColumnIndex-1] ).booleanValue();
  }

  public byte getByte( String pColumnName  ) throws SQLException {
    return getByte( findColumn(pColumnName) );
  }

  public byte getByte( int pColumnIndex  ) throws SQLException {
    return iRecord[pColumnIndex-1].getBytes()[0];
  }

  public byte[] getBytes( String pColumnName  ) throws SQLException {
    return getBytes(findColumn(pColumnName));
  }

  public byte[] getBytes( int pColumnIndex  ) throws SQLException {
    return iRecord[pColumnIndex-1].getBytes();
  }

  public double getDouble( String pColumnName  ) throws SQLException {
    return getDouble(findColumn(pColumnName));
  }

  public double getDouble( int pColumnIndex  ) throws SQLException {
    return Double.parseDouble(iRecord[pColumnIndex-1]);
  }

  public float getFloat( String pColumnName  ) throws SQLException {
    return getFloat(findColumn(pColumnName));
  }

  public float getFloat( int pColumnIndex  ) throws SQLException {
    return Float.parseFloat(iRecord[pColumnIndex-1]);
  }

  public int getInt( String pColumnName  ) throws SQLException {
    return getInt(findColumn(pColumnName));
  }

  public int getInt( int pColumnIndex  ) throws SQLException {
    return Integer.parseInt(iRecord[pColumnIndex-1]);
  }

  public InputStream getAsciiStream( String pColumnName  ) throws SQLException {
    return null;
  }

  public InputStream getAsciiStream( int pColumnIndex  ) throws SQLException {
    return null;
  }

  public InputStream getBinaryStream( String pColumnName  )  throws SQLException {
    return null;
  }

  public InputStream getBinaryStream( int pColumnIndex  )  throws SQLException {
    return null;
  }

  public InputStream getUnicodeStream( String pColumnName  ) throws SQLException {
    return null;
  }

  public InputStream getUnicodeStream( int pColumnIndex  ) throws SQLException {
    return null;
  }

  public Reader getCharacterStream( String pColumnName  ) throws SQLException {
    return null;
  }

  public Reader getCharacterStream( int pColumnIndex  ) throws SQLException {
    return null;
  }

  public URL getURL( String pColumnName  ) throws SQLException {
    return getURL( findColumn(pColumnName) );
  }

  public URL getURL( int pColumnIndex  ) throws SQLException {
    try {
      return new URL( iRecord[pColumnIndex-1] );
    }
    catch( Exception e ) {
      throw new SQLException( e.getMessage() );
    }
  }

  public Date getDate( String pColumnName  ) throws SQLException {
    return getDate( findColumn(pColumnName) );
  }

  public Date getDate( String pColumnName, Calendar pCalendar  ) throws SQLException {
    return getDate( findColumn(pColumnName), pCalendar );
  }

  public Date getDate( int pColumnIndex  ) throws SQLException {
    return getDate( pColumnIndex, null );
  }

  /** ignores Calendar */
  public Date getDate( int pColumnIndex, Calendar pCalendar  ) throws SQLException {
    try {
      java.util.Date d = iDateFormat.parse( iRecord[pColumnIndex-1] );
      return new Date( d.getTime() );
    }
    catch( Exception e ) {
      throw new SQLException( e.getMessage() );
    }
  }

  public Time getTime( String pColumnName  ) throws SQLException {
    return getTime(findColumn(pColumnName));
  }

  public Time getTime( String pColumnName, Calendar pCalendar ) throws SQLException {
    return getTime(findColumn(pColumnName), null );
  }

  public Time getTime( int pColumnIndex  ) throws SQLException {
    return getTime( pColumnIndex, null );
  }


  /** Note: ignores Calendar. */
  public Time getTime( int pColumnIndex, Calendar pCalendar ) throws SQLException {
    return new Time( getLong(pColumnIndex) );
  }

  public Timestamp getTimestamp( String pColumnName ) throws SQLException {
    return getTimestamp(findColumn(pColumnName));
  }

  public Timestamp getTimestamp( String pColumnName, Calendar pCalendar )  throws SQLException {
    return getTimestamp(findColumn(pColumnName), pCalendar );
  }

  public Timestamp getTimestamp( int pColumnIndex ) throws SQLException {
    return getTimestamp(pColumnIndex,null);
  }


  /** Note: ignores Calendar. */
  public Timestamp getTimestamp( int pColumnIndex, Calendar pCalendar )  throws SQLException {
    try {
      java.util.Date d = iDateFormat.parse( iRecord[pColumnIndex-1] );
      return new Timestamp( d.getTime() );
    }
    catch( Exception e ) {
      throw new SQLException( e.getMessage() );
    }
  }

  public long getLong( String pColumnName  ) throws SQLException {
    return getLong(findColumn(pColumnName));
  }

  public long getLong( int pColumnIndex  ) throws SQLException {
    return Long.parseLong( iRecord[pColumnIndex-1] );
  }

  public short getShort( String pColumnName  ) throws SQLException {
    return getShort(findColumn(pColumnName));
  }

  public short getShort( int pColumnIndex  ) throws SQLException {
    return Short.parseShort( iRecord[pColumnIndex-1] );
  }



  // protected 

  /** Move to correct data line. */
  protected boolean moveToLine() {
    boolean inside = -1 < iRecordIndex && iRecordIndex < iData.size(); 
    if( inside ) {
      iRecord = (String[]) iData.get( (int) iRecordIndex );
    }
    return inside;
  }



  // private

  /** Returns <code>List</code> of <code>String[]</code> arrays as <code>String</code>. */
  private String makeString( List pData ) {
    StringBuffer sb = new StringBuffer( pData.size() * 55 );
    sb.append("[");
    for( Iterator rT = pData.iterator(); rT.hasNext(); ) {
      sb.append( TextUtil.array2text( (String[]) rT.next() ) );
      sb.append( "|" );
    }
    sb.append("]");
    return sb.toString();
  }  

}
Syntax Highlighting created using the com.Ostermiller.Syntax package.
Thursday, February 23 2006 at 16:47