/////////////////////////////////////////////////////////////////////////////
// Copyright (c) 1999, COAS, Oregon State University
// ALL RIGHTS RESERVED. U.S. Government Sponsorship acknowledged.
//
// Please read the full copyright notice in the file COPYRIGHT
// in this directory.
//
// Author: Nathan Potter (ndp@oce.orst.edu)
//
// College of Oceanic and Atmospheric Scieneces
// Oregon State University
// 104 Ocean. Admin. Bldg.
// Corvallis, OR 97331-5503
//
/////////////////////////////////////////////////////////////////////////////
package dods.servers.sql;
import java.io.*;
import java.util.*;
import java.sql.*;
import dods.util.*;
import dods.dap.*;
import dods.dap.Server.*;
/**
* Holds a DODS Server <code>Sequence</code> value.
*
* @version $Revision: 1.4 $
* @author ndp
* @see BaseType
*/
public class sqlSeq extends SDSequence {
private static final boolean _Debug = false;
private int rowCount = 0;
/** Constructs a new <code>test_SDSequence</code>. */
public sqlSeq() {
super();
}
/**
* Constructs a new <code>test_SDSequence</code> with name <code>n</code>.
* @param n the name of the variable.
*/
public sqlSeq(String n) {
super(n);
}
// --------------- FileIO Interface
/** Read a value from the named dataset for this variable.
This implementation is intended to be reading data from
a JDBC connection to a relational database.
<p>
Relational databases appear relatively "flat" to DODS. By
this we mean that DODS datasets can have very complex
multilevel structure. Relational databases appear to DODS as a
dataset populated by one or more Sequences, each one representing
a table in the database. The table contents are generally
simple types, or arrays of bytes. Since relational databases
support cross table (and thus cross sequence) queries and since
they return the results of these queries in a single "table
like" object, we must take care to unpack this returned data into
the appropriate members of the DDS representation of the dataset. The
read() method of the Sequence type plays a key roll in this, along
with the read() methods of the simple types and the send() method of
the CEEvaluator.</p>
<p>
This Sequence read() method handles "rewinding" the currentColumn index
in the sqlResponse object to insure that for as long as there is more data to
be read into this Sequence that the currentColumn is set correctly for each
invocation of this method. In addition, this method handles the task
of moving the ResultSet object in the sqlResponse through the rows of
the response data, insuring that at each invocation of a top level sequence
read() invocation the ResultSet is set up for a new row of data.
@param datasetName String identifying the file or other data store
from which to read a vaue for this variable.
@param specialO This <code>Object</code> is used by this method. It is
assumed to be of type sqlResponse, a container for the ResultSet and
the index value of next column to evaluate.
@return <code>true</code> if more data remains to be read, otherwise
<code>false</code>.
@exception NoSuchVariableException
@exception IOException
@exception EOFException
*/
public boolean read(String datasetName, Object specialO)
throws NoSuchVariableException, IOException, EOFException {
boolean retVal, addRow = false;
sqlResponse res = (sqlResponse) specialO;
// Cache the current column. We need to do this so that: As this
// Sequence is serialized it moves through the ResultSet row by row
// reading some number of consecutive columns from each row.
// In order for the column counter to be correctly positioned
// at the begining of each call to read() we need to cache that
// first currentColumn and use it to restore the currentColumn pointer
// at the end of read()
int startColumn = res.getCurrentColumn();
if (_Debug) System.out.println("\nReading row " + rowCount + " of Sequence \"" + getName() + "\" from " + datasetName + ":");
Enumeration enumx = this.getVariables();
while (enumx.hasMoreElements()) {
ServerMethods sm = (ServerMethods) enumx.nextElement();
//System.out.println("Reading variable: "+((BaseType)sm).getName());
if (sm.isProject()) {
sm.read(datasetName, specialO);
//((BaseType)sm).printVal(System.out," ");
}
}
boolean moreToRead = false;
if (_Debug)
System.out.println("Sequence " +
getName() +
" startColumn: " +
startColumn +
" currentColumn: " +
res.getCurrentColumn());
// Check and make sure not to move to the next row of results if we aren't at the highest
// level...
if (getLevel() == 0) {
try {
// Try to get next row.
moreToRead = res.getResultSet().next();
} catch (SQLException sqle) {
throw new IOException(sqle.toString());
}
}
// Artifcially limit the response evaluation to _maxRows
rowCount++;
if (rowCount >= res.getMaxRows()) {
moreToRead = false;
}
setRead(true);
// If there are more rows left in the ResultSet (thus
// more data to read in this Sequence) reposition the
// currentColumn pointer so that it's at the begining
// of the rows relevent for this Sequence when the
// flow of control re-enters this read() method.
if (moreToRead) {
if (_Debug) System.out.println("Resetting Current Column to: " + startColumn);
res.setCurrentColumn(startColumn);
}
//System.out.println("Read finished. Returning");
return (moreToRead);
}
/**
* Server-side serialization for DODS variables (sub-classes of
* <code>BaseType</code>).
* We override the serialize() method of the parent SD<i>Class</i> in
* order to stop the evaluation of the CEEvaluator's Clauses, as
* this has been handled implicitly by the SQL Database that this
* Server is designed to interrogate.
*
* @param sink a <code>DataOutputStream</code> to write to.
* @exception IOException thrown on any <code>OutputStream</code> exception.
* @see BaseType
* @see DDS
* @see ServerDDS */
public void serialize(String dataset, DataOutputStream sink, CEEvaluator ce, Object specialO)
throws NoSuchVariableException, SDODSException, IOException {
boolean moreToRead = true;
while (moreToRead) {
if (!isRead()) {
// ************* Pulled out the getLevel() check in order to support the "new"
// and "improved" serialization of dods sequences. 8/31/01 ndp
// if(getLevel() != 0 ) // Read only the outermost level
// return;
moreToRead = read(dataset, specialO);
}
// ************* Pulled out the getLevel() check in order to support the "new"
// and "improved" serialization of dods sequences. 8/31/01 ndp
// if(getLevel() == 0){
writeMarker(sink, START_OF_INSTANCE);
// }
for (Enumeration e = varTemplate.elements(); e.hasMoreElements();) {
ServerMethods sm = (ServerMethods) e.nextElement();
if (sm.isProject()) {
if (_Debug) System.out.println("Sending variable: " + ((BaseType) sm).getName());
sm.serialize(dataset, sink, ce, specialO);
}
}
if (moreToRead)
setAllReadFlags(false);
}
// ************* Pulled out the getLevel() check in order to support the "new"
// and "improved" serialization of dods sequences. 8/31/01 ndp
// if(getLevel() == 0){
writeMarker(sink, END_OF_SEQUENCE);
// }
return;
}
}