/////////////////////////////////////////////////////////////////////////////
// Copyright (c) 1998, California Institute of Technology.
// ALL RIGHTS RESERVED. U.S. Government Sponsorship acknowledged.
//
// Please read the full copyright notice in the file COPYRIGHT
// in this directory.
//
// Author: Jake Hamby, NASA/Jet Propulsion Laboratory
// Jake.Hamby@jpl.nasa.gov
/////////////////////////////////////////////////////////////////////////////
package dods.dap;
import java.io.*;
/**
* This class holds a one-dimensional array of DODS data types.
* It is the parent of both <code>DList</code> and <code>DArray</code>.
* This class uses a <code>PrimitiveVector</code> to hold the data and
* deserialize it, thus allowing more efficient storage to be used for the
* primitive types.
*
* @version $Revision: 1.3 $
* @author jehamby
* @see BaseType
* @see DArray
* @see DList
* @see PrimitiveVector
*/
abstract public class DVector extends BaseType implements ClientIO {
/**
* The values in this <code>DVector</code>, stored in a
* <code>PrimitiveVector</code>.
*/
private PrimitiveVector vals;
/** Constructs a new <code>DVector</code>. */
public DVector() {
super();
}
/**
* Returns the DODS type name of the class instance as a <code>String</code>.
* @return the DODS type name of the class instance as a <code>String</code>.
*/
public String getTypeName() {
return "Vector";
}
/**
* Constructs a new <code>DVector</code> with name <code>n</code>.
* @param n the name of the variable.
*/
public DVector(String n) { super(n); }
/**
* Returns a clone of this <code>DVector</code>. A deep copy is performed on
* all variables inside the <code>DVector</code>.
*
* @return a clone of this <code>DVector</code>.
*/
public Object clone() {
DVector v = (DVector)super.clone();
v.vals = (PrimitiveVector)vals.clone();
return v;
}
/**
* Returns the number of elements in the vector.
* @return the number of elements in the vector.
*/
public int getLength() {
if (vals == null)
return 0;
else
return vals.getLength();
}
/**
* Sets the number of elements in the vector. Allocates a new
* array of the desired size. Note that if this is called multiple times,
* the old array and its contents will be lost!
* <p>
* Only called inside of <code>deserialize</code> method or in derived
* classes on server.
*
* @param len the number of elements in the array.
*/
public void setLength(int len) {
vals.setLength(len);
}
/**
* Adds a variable to the container.
* @param v the variable to add.
*/
public void addVariable(BaseType v) {
vals = v.newPrimitiveVector();
setName(v.getName());
}
/**
* Returns the <code>PrimitiveVector</code> for this vector. This can be
* cast to the appropriate type and used by a DODS client to read or set
* individual values in the vector.
*
* @return the attached <code>PrimitiveVector</code>.
*/
public PrimitiveVector getPrimitiveVector() {
return vals;
}
/**
* Write the variable's declaration in a C-style syntax. This
* function is used to create textual representation of the Data
* Descriptor Structure (DDS). See <em>The DODS User Manual</em> for
* information about this structure.
*
* @param os The <code>PrintWriter</code> on which to print the
* declaration.
* @param space Each line of the declaration will begin with the
* characters in this string. Usually used for leading spaces.
* @param print_semi a boolean value indicating whether to print a
* semicolon at the end of the declaration.
*
* @see BaseType#printDecl(PrintWriter, String, boolean)
*/
public void printDecl(PrintWriter os, String space,
boolean print_semi, boolean constrained) {
// BEWARE! Since printDecl()is (multiple) overloaded in BaseType
// and all of the different signatures of printDecl() in BaseType
// lead to one signature, we must be careful to override that
// SAME signature here. That way all calls to printDecl() for
// this object lead to this implementation.
//os.println("DVector.printDecl()");
os.print(space + getTypeName());
vals.printDecl(os, " ", print_semi,constrained);
}
/**
* Prints the value of the variable, with its declaration. This
* function is primarily intended for debugging DODS applications and
* text-based clients such as geturl.
*
* @param os the <code>PrintWriter</code> on which to print the value.
* @param space this value is passed to the <code>printDecl</code> method,
* and controls the leading spaces of the output.
* @param print_decl_p a boolean value controlling whether the
* variable declaration is printed as well as the value.
* @see BaseType#printVal(PrintWriter, String, boolean)
*/
public void printVal(PrintWriter os, String space, boolean print_decl_p) {
if (print_decl_p) {
printDecl(os, space, false);
os.print(" = ");
}
os.print("{ ");
vals.printVal(os, "");
if (print_decl_p)
os.println("};");
else
os.print("}");
}
/**
* Reads data from a <code>DataInputStream</code>. This method is only used
* on the client side of the DODS client/server connection.
*
* @param source a <code>DataInputStream</code> to read from.
* @param sv the <code>ServerVersion</code> returned by the server.
* @param statusUI the <code>StatusUI</code> object to use for GUI updates
* and user cancellation notification (may be null).
* @exception EOFException if EOF is found before the variable is completely
* deserialized.
* @exception IOException thrown on any other InputStream exception.
* @exception DataReadException if an unexpected value was read.
* @see ClientIO#deserialize(DataInputStream, ServerVersion, StatusUI)
*/
public synchronized void deserialize(DataInputStream source,
ServerVersion sv,
StatusUI statusUI)
throws IOException,
EOFException,
DataReadException {
// Because arrays of primitive types (ie int32, float32, byte, etc) are
// handled in the C++ core using the XDR package we must read the
// length twice for those types. For BaseType vectors, we should read
// it only once. This is in effect a work around for a bug in the C++
// core as the C++ core does not consume 2 length values for the
// BaseType vectors. Bummer...
int length = source.readInt();
if(!(vals instanceof BaseTypePrimitiveVector)){
// because both XDR and DODS write the length, we must read it twice
int length2 = source.readInt();
//System.out.println("array1 length read: "+getName()+" "+length+ " -- "+length2);
//System.out.println(" array type = : "+vals.getClass().getName());
// QC the second length
if(length != length2) {
throw new DataReadException("Inconsistent array length read: "+length+ " != "+length2);
}
} /* else {
System.out.println("array2 length read: "+getName()+" "+length);
System.out.println(" array type = : "+vals.getClass().getName());
} */
if(length < 0)
throw new DataReadException("Negative array length read.");
if(statusUI != null)
statusUI.incrementByteCount(8);
vals.setLength(length);
vals.deserialize(source, sv, statusUI);
}
/**
* Writes data to a <code>DataOutputStream</code>. This method is used
* primarily by GUI clients which need to download DODS data, manipulate
* it, and then re-save it as a binary file.
*
* @param sink a <code>DataOutputStream</code> to write to.
* @exception IOException thrown on any <code>OutputStream</code>
* exception.
*/
public void externalize(DataOutputStream sink) throws IOException {
// Because arrays of primitive types (ie int32, float32, byte, etc) are
// handled in the C++ core using the XDR package we must write the
// length twice for those types. For BaseType vectors, we should write
// it only once. This is in effect a work around for a bug in the C++
// core as the C++ core does not consume 2 length values for thge
// BaseType vectors. Bummer...
int length = vals.getLength();
sink.writeInt(length);
if(!(vals instanceof BaseTypePrimitiveVector)){
// because both XDR and DODS write the length, we must write it twice
sink.writeInt(length);
}
vals.externalize(sink);
}
}