opendap.dap
Class DDS

java.lang.Object
  extended by opendap.dap.BaseType
      extended by opendap.dap.DConstructor
          extended by opendap.dap.DStructure
              extended by opendap.dap.DDS
All Implemented Interfaces:
java.io.Serializable, java.lang.Cloneable, ClientIO
Direct Known Subclasses:
DataDDS, ServerDDS

public class DDS
extends DStructure

The OPeNDAP Data Descriptor Object (DDS) is a data structure used by the OPeNDAP software to describe datasets and subsets of those datasets. The DDS may be thought of as the declarations for the data structures that will hold data requested by some OPeNDAP client. Part of the job of a OPeNDAP server is to build a suitable DDS for a specific dataset and to send it to the client. Depending on the data access API in use, this may involve reading part of the dataset and inferring the DDS. Other APIs may require the server simply to read some ancillary data file with the DDS in it.

On the server side, in addition to the data declarations, the DDS holds the clauses of any constraint expression that may have accompanied the data request from the OPeNDAP client. The DDS object includes methods for modifying the DDS according to the given constraint expression. It also has methods for directly modifying a DDS, and for transmitting it from a server to a client.

For the client, the DDS object includes methods for reading the persistent form of the object sent from a server. This includes parsing the ASCII representation of the object and, possibly, reading data received from a server into a data object.

Note that the class DDS is used to instantiate both DDS and DataDDS objects. A DDS that is empty (contains no actual data) is used by servers to send structural information to the client. The same DDS can becomes a DataDDS when data values are bound to the variables it defines.

For a complete description of the DDS layout and protocol, please refer to The OPeNDAP User Guide.

The DDS has an ASCII representation, which may be transmitted from a OPeNDAP server to a client. Here is the DDS representation of an entire dataset containing a time series of worldwide grids of sea surface temperatures:

  Dataset {
      Float64 lat[lat = 180];
      Float64 lon[lon = 360];
      Float64 time[time = 404];
      Grid {
       ARRAY:
          Int32 sst[time = 404][lat = 180][lon = 360];
       MAPS:
          Float64 time[time = 404];
          Float64 lat[lat = 180];
          Float64 lon[lon = 360];
      } sst;
  } weekly;
 

If the data request to this dataset includes a constraint expression, the corresponding DDS might be different. For example, if the request was only for northern hemisphere data at a specific time, the above DDS might be modified to appear like this:

  Dataset {
      Grid {
       ARRAY:
          Int32 sst[time = 1][lat = 90][lon = 360];
       MAPS:
          Float64 time[time = 1];
          Float64 lat[lat = 90];
          Float64 lon[lon = 360];
      } sst;
  } weekly;
 

Since the constraint has narrowed the area of interest, the range of latitude values has been halved, and there is only one time value in the returned array. Note that the simple arrays (lat, lon, and time) described in the dataset are also part of the sst Grid object. They can be requested by themselves or as part of that larger object.

DDX

The DDS also has an XML representation. This is known as a DDX. Since BaseType variables now each have their own set of Attributes it has become necessary to have a representation of the DDS that captures these relationships. Consider the previous example. A correctly constructed DAS for that DDS might look like:
 Attributes {
 lat {
 String fullName "latitude";
 String units "degrees North";
 }
 lon {
 String fullName "longitude";
 String units "degrees East";
 }
 time {
 String units "seconds";
 }
 sst {
 String fullName "Sea Surface Temperature";
 String units "degrees centigrade";
 sst {
 Alias fullName .sst.fullName;
 Alias units .sst.units;
 }
 time {
 Alias units .time.units;
 }
 lat {
 Alias fullName .lat.fullName;
 Alias units .lat.units;
 }
 lon {
 Alias fullName .lon.fullName;
 Alias units .lon.units;
 }
 }
 }
 

Combined with the DDS and expressed as a DDX it would look like:

 

<?xml version="1.0" encoding="UTF-8"?> <Dataset name="weekly" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xml.opendap.org/ns/DAP2" xsi:schemaLocation="http://xml.opendap.org/ns/DAP2 http://xml.opendap.org/dap/dap2.xsd" >

<Array name="lat"> <Attribute name="fullName" type="String"> <value>&quot;latitude&quot;</value> </Attribute> <Attribute name="units" type="String"> <value>&quot;degrees North&quot;</value> </Attribute> <Float64/> <dimension name="lat" size="180"/> </Array> <Array name="lon"> <Attribute name="fullName" type="String"> <value>&quot;longitude&quot;</value> </Attribute> <Attribute name="units" type="String"> <value>&quot;degrees East&quot;</value> </Attribute> <Float64/> <dimension name="lon" size="360"/> </Array> <Array name="time"> <Attribute name="units" type="String"> <value>&quot;seconds&quot;</value> </Attribute> <Float64/> <dimension name="time" size="404"/> </Array> <Grid name="sst"> <Attribute name="fullName" type="String"> <value>&quot;Sea Surface Temperature&quot;</value> </Attribute> <Attribute name="units" type="String"> <value>&quot;degrees centigrade&quot;</value> </Attribute> <Array name="sst"> <Alias name="fullName" Attribute=".sst.fullName"/> <Alias name="units" Attribute=".sst.units"/> <Int32/> <dimension name="time" size="404"/> <dimension name="lat" size="180"/> <dimension name="lon" size="360"/> </Array> <Map name="time"> <Alias name="units" Attribute=".time.units"/> <Float64/> <dimension name="time" size="404"/> </Map> <Map name="lat"> <Alias name="fullName" Attribute=".lat.fullName"/> <Alias name="units" Attribute=".lat.units"/> <Float64/> <dimension name="lat" size="180"/> </Map> <Map name="lon"> <Alias name="fullName" Attribute=".lon.fullName"/> <Alias name="units" Attribute=".lon.units"/> <Float64/> <dimension name="lon" size="360"/> </Map> </Grid>

<dataBLOB href="cid:ContentIdOfTheMIMEAttcahmentContainingTheDataBlob"/> </Dataset>

The DDX can also be sent from a server to a client.

Using the DDS's API to construct a DDS

Many developers choose not to use the DDSParser to build DDS's but to build them using the DDS API. This is typical of devlopers writing servers that work with information rich data formats such as NetCDF or HDF. With the addition of Attributes (and Attribute containers) to all of the datatypes in the DAP it is now possible to construct a DDS that contains all of the source meta-data from the original data source. This is an extremly useful thing. However, when building a DDS using the DDS API be sure to call the functions DDS.checkForAttributeNameConflict() and DDS.resolveAliases() on the new DDS prior to releasing it from the code that builds it. Otherwise the DDS may have functional problems!

See The OPeNDAP User Guide, or the documentation of the BaseType class for descriptions of the OPeNDAP data types.

Version:
$Revision: 23881 $
Author:
ndp
See Also:
BaseType, BaseTypeFactory, DAS, DDSXMLParser, checkForAttributeNameConflict(), resolveAliases(), Serialized Form

This class/method is associated with pre-release version of the DDX API. It is experimental and is subject to (significant) change.

Many parts of this class have been modified to support the DDX functionality. This API is going to change!

Field Summary
 
Fields inherited from class opendap.dap.DStructure
vars
 
Constructor Summary
DDS()
          Creates an empty DDS.
DDS(BaseTypeFactory factory)
          Creates an empty DDS with the given BaseTypeFactory.
DDS(java.lang.String n)
          Creates an empty DDS with the given dataset name.
DDS(java.lang.String n, BaseTypeFactory factory)
          Creates an empty DDS with the given dataset name and BaseTypeFactory.
DDS(java.lang.String n, BaseTypeFactory factory, java.lang.String schema)
          Creates an empty DDS with the given dataset name and BaseTypeFactory.
 
Method Summary
 void addVariable(BaseType v, int part)
          Adds a variable to the container.
 void checkForAttributeNameConflict()
          Check for name conflicts.
 void checkSemantics(boolean all)
          Check the semantics of the DDS.
 java.lang.Object clone()
          Returns a clone of this DDS.
 void delVariable(java.lang.String name)
          Removes a variable from the DDS.
 java.lang.String getBlobContentID()
          Get's the dataBLOB Contnet-ID for this DDS.
 DAS getDAS()
          Creates a DAS object from the collection of BaseType variables and their associated Attributes.
 java.lang.String getDDSText()
          This a wrapper method for DDS.print().
 java.lang.String getDDXText()
          This a wrapper method for DDS.printXML().
 BaseTypeFactory getFactory()
          Get the Class factory.
 BaseType getVariable(java.lang.String name)
          Returns a reference to the named variable.
 java.util.Enumeration getVariables()
          Returns an Enumeration of the dataset variables.
 void ingestDAS(DAS das)
          Takes the passed parameter das and attempts to incorporate it's contents into the Attributes of the DDS variables.
static java.lang.String normalize(java.lang.String field)
          The normalize method is used to normalize variable and attribute name strings prior to their comparison with the normalized tokens extracted from the variable and name fields in an Alias declaration.
 int numVariables()
          Returns the number of variables in the dataset.
 void parse(java.io.InputStream is)
          Reads a DDS from the named InputStream or Reader.
 void parseXML(org.jdom.Document ddxDoc, boolean validation)
          Reads a DDX from the named Document.
 void parseXML(java.io.InputStream is, boolean validation)
          Reads a DDX from the named InputStream.
 void print(java.io.OutputStream os)
          Print the DDS on the given OutputStream.
 void print(java.io.PrintWriter os)
          Print the DDS on the given PrintWriter.
 void printDAS(java.io.OutputStream os)
          Print a DAS constructed from this DDS and it's BaseType variables.
 void printDAS(java.io.PrintWriter pw)
          Print a DAS constructed from this DDS and it's BaseType variables.
 void printXML(java.io.PrintWriter pw)
          Prints the peristent representation of the DDS as an XML document.
 void printXML(java.io.PrintWriter pw, java.lang.String pad, boolean constrained)
          Prints the peristent representation of the DDS as an XML document.
 void resolveAliases()
          Before the DDS can be used all of the Aliases in the various AttributeTables must be resolved.
 java.util.Stack search(java.lang.String name, java.util.Stack compStack)
          Look for name in the DDS.
 void setBlobContentID(java.lang.String contentID)
          Set's the dataBLOB reference for this DDS.
 void setFactory(BaseTypeFactory btf)
          Get the Class factory.
static java.util.Vector tokenizeAliasField(java.lang.String field)
          The tokenizeAliasFiled() method is used to tokenize the variable and the attribute fields in the alias declaration.
 
Methods inherited from class opendap.dap.DStructure
deserialize, elementCount, externalize, getTypeName, getVar, printDecl, printVal
 
Methods inherited from class opendap.dap.DConstructor
addVariable, someChildHasAttributes
 
Methods inherited from class opendap.dap.BaseType
addAttributeAlias, addAttributeContainer, appendAttribute, appendAttribute, appendAttributeContainer, checkSemantics, delAttribute, delAttribute, elementCount, getAttribute, getAttribute, getAttributeNames, getAttributeTable, getClearName, getLongName, getName, getParent, hasAttributes, newPrimitiveVector, printAttributes, printAttributes, printAttributes, printAttributes, printDecl, printDecl, printDecl, printDecl, printDecl, printDecl, printDecl, printVal, printVal, printVal, printXML, printXML, printXML, setClearName, setName, setParent
 
Methods inherited from class java.lang.Object
equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

DDS

public DDS()
Creates an empty DDS.


DDS

public DDS(java.lang.String n)
Creates an empty DDS with the given dataset name.

Parameters:
n - the dataset name

DDS

public DDS(BaseTypeFactory factory)
Creates an empty DDS with the given BaseTypeFactory. This will be used for OPeNDAP servers which need to construct subclasses of the various BaseType objects to hold additional server-side information.

Parameters:
factory - the server BaseTypeFactory object.

DDS

public DDS(java.lang.String n,
           BaseTypeFactory factory)
Creates an empty DDS with the given dataset name and BaseTypeFactory. This will be used for OPeNDAP servers which need to construct subclasses of the various BaseType objects to hold additional server-side information.

Parameters:
n - the dataset name
factory - the server BaseTypeFactory object.

DDS

public DDS(java.lang.String n,
           BaseTypeFactory factory,
           java.lang.String schema)
Creates an empty DDS with the given dataset name and BaseTypeFactory. This will be used for OPeNDAP servers which need to construct subclasses of the various BaseType objects to hold additional server-side information.

Parameters:
n - the dataset name
factory - the server BaseTypeFactory object.
schema - the URL where the parser can find an instance of the OPeNDAP namespace schema.

This class/method is associated with pre-release version of the DDX API. It is experimental and is subject to (significant) change.

Method Detail

clone

public java.lang.Object clone()
Returns a clone of this DDS. A deep copy is performed on all variables inside the DDS.

Overrides:
clone in class DStructure
Returns:
a clone of this DDS.

getFactory

public final BaseTypeFactory getFactory()
Get the Class factory. This is the machine that builds classes for the internal representation of the data set.

Returns:
the BaseTypeFactory.

setFactory

public final void setFactory(BaseTypeFactory btf)
Get the Class factory. This is the machine that builds classes for the internal representation of the data set.


setBlobContentID

public void setBlobContentID(java.lang.String contentID)
Set's the dataBLOB reference for this DDS. The dataBLOB element has an attribute, href, which is used to reference the MIME part of a the Multipart MIME document in a DAP4 data response that contains the binary encoded data described by the DDX document.

Parameters:
contentID - A String containing the Content-ID of the MIME part that contains the binary encoded data represented by this DDS.

This class/method is associated with pre-release version of the DDX API. It is experimental and is subject to (significant) change.


getBlobContentID

public java.lang.String getBlobContentID()
Get's the dataBLOB Contnet-ID for this DDS. The dataBLOB element has an attribute, href, which is used to reference the MIME part of a the Multipart MIME document in a DAP4 data response that contains the binary encoded data described by the DDX document.

Returns:
A String containing the URL of the servers BLOB response for this DDS.

This class/method is associated with pre-release version of the DDX API. It is experimental and is subject to (significant) change.


getDAS

public DAS getDAS()
           throws DASException
Creates a DAS object from the collection of BaseType variables and their associated Attributes. This DAS is correctly formed (vis-a-vis the DAP specification) for this DDS.

Returns:
A correctly formed DAS object for this DDS.
Throws:
DASException
See Also:
DAS, BaseType

printDAS

public void printDAS(java.io.OutputStream os)
Print a DAS constructed from this DDS and it's BaseType variables.

Parameters:
os - The OutputStream to print to.

printDAS

public void printDAS(java.io.PrintWriter pw)
Print a DAS constructed from this DDS and it's BaseType variables.

Parameters:
pw - The PrintWriter to print to.

delVariable

public void delVariable(java.lang.String name)
Removes a variable from the DDS. Does nothing if the variable can't be found. If there are multiple variables with the same name, only the first will be removed. To detect this, call the checkSemantics method to verify that each variable has a unique name.

Parameters:
name - the name of the variable to remove.
See Also:
checkSemantics(boolean)

getVariable

public BaseType getVariable(java.lang.String name)
                     throws NoSuchVariableException
Returns a reference to the named variable.

Overrides:
getVariable in class DStructure
Parameters:
name - the name of the variable to return.
Returns:
the variable named name.
Throws:
NoSuchVariableException - if the variable isn't found.

addVariable

public void addVariable(BaseType v,
                        int part)
Adds a variable to the container. This overrides the getVariable() in DStructure in order to keep the parent value from getting set. Otherwise the name of the DDS (which is typically the name of the Dataset) will appear in calls to BaseType.getLongName().

This might be a mistake!!! Watch out for bugs induced by this method.

Overrides:
addVariable in class DStructure
Parameters:
v - the variable to add.
part - ignored for DSequence.

search

public java.util.Stack search(java.lang.String name,
                              java.util.Stack compStack)
                       throws NoSuchVariableException
Look for name in the DDS. Start the search using the ctor variable (or array/list of ctors) found on the top of the Stack compStack (for component stack). When the named variable is found, return the stack compStack modified so that it now contains each ctor-type variable that on the path to the named variable. If the variable is not found after exhausting all possibilities, throw NoSuchVariable.

Note: This method takes the stack as a parameter so that it can be used by a parser that is working through a list of identifiers that represents the path to a variable as well as a shorthand notation for the identifier that is the equivalent to the leaf node name alone. In the form case the caller helps build the stack by repeatedly calling search, in the latter case this method must build the stack itself. This method is over kill for the first case.

Parameters:
name - Search for the named variable.
compStack - The component stack. This holds the BaseType variables that match the each component of a specific variable's name. This method starts its search using the element at the top of the stack and adds to the stack. The order of BaseType variables on the stack is the reverse of the tree-traverse order. That is, the top most element on the stack is the BaseType for the named variable, under that is the named variable's parent and so on.
Returns:
A stack of BaseType variables which hold the path from the top of the DDS to the named variable.
Throws:
NoSuchVariableException

getVariables

public final java.util.Enumeration getVariables()
Returns an Enumeration of the dataset variables.

Overrides:
getVariables in class DStructure
Returns:
an Enumeration of BaseType.

numVariables

public final int numVariables()
Returns the number of variables in the dataset.

Returns:
the number of variables in the dataset.

parse

public void parse(java.io.InputStream is)
           throws ParseException,
                  DDSException
Reads a DDS from the named InputStream or Reader. This method calls a generated parser to interpret an ASCII representation of a DDS, and regenerate that DDS in memory. This method does the following:

This method does NOT need to call DDS.checkForAttributeNameConflict() or DDS.resolveAliases() as the syntax of the DDS does not support the inclusion of Attribute or Alias members.

Parameters:
is - the InputStream containing the DDS to parse.
Throws:
ParseException - thrown on a parser error.
DDSException - thrown on an error constructing the DDS.
See Also:
DDSParser, DDSXMLParser

parseXML

public void parseXML(java.io.InputStream is,
                     boolean validation)
              throws DAP2Exception
Reads a DDX from the named InputStream. This method calls a generated parser to interpret an XML representation of a DDS (aka a DDX), and instantiate that DDS in memory. This method does the following:

The last two items should be called EVERY time a DDS is populated with variables ( by a parser, or through the DDS API) and prior to releasing it for use to any calling program.

Parameters:
is - the InputStream containing the DDS to parse.
validation - Is a boolean indicating whether or not the parser should validate the XML document using the Schema (typically referenced in the document itself). In general server side applications should always vaidate, while clients shouldn't bother (since they are ostensibly receiving the document from a server that has already done so.)
Throws:
DDSException - thrown on an error constructing the DDS.
DAP2Exception
See Also:
DDSXMLParser, checkForAttributeNameConflict(), resolveAliases()

This class/method is associated with pre-release version of the DDX API. It is experimental and is subject to (significant) change.


parseXML

public void parseXML(org.jdom.Document ddxDoc,
                     boolean validation)
              throws DAP2Exception
Reads a DDX from the named Document. This method calls a generated parser to interpret an XML representation of a DDS (aka a DDX), and instantiate that DDS in memory. This method does the following:

The last two items should be called EVERY time a DDS is populated with variables ( by a parser, or through the DDS API) and prior to releasing it for use to any calling program.

Parameters:
ddxDoc - A JDOM Document containing the DDS to parse.
validation - Is a boolean indicating whether or not the parser should validate the XML document using the Schema (typically referenced in the document itself). In general server side applications should always vaidate, while clients shouldn't bother (since they are ostensibly receiving the document from a server that has already done so.)
Throws:
DDSException - thrown on an error constructing the DDS.
DAP2Exception
See Also:
DDSXMLParser, checkForAttributeNameConflict(), resolveAliases()

This class/method is associated with pre-release version of the DDX API. It is experimental and is subject to (significant) change.


checkSemantics

public void checkSemantics(boolean all)
                    throws BadSemanticsException
Check the semantics of the DDS. If all is true, check not only the semantics of the DDS itself, but also recursively check all variables in the dataset.

Overrides:
checkSemantics in class DStructure
Parameters:
all - this flag indicates whether to check the semantics of the member variables, too.
Throws:
BadSemanticsException - if semantics are bad
See Also:
BaseType.checkSemantics(boolean)

print

public void print(java.io.PrintWriter os)
Print the DDS on the given PrintWriter.

Parameters:
os - the PrintWriter to use for output.

print

public final void print(java.io.OutputStream os)
Print the DDS on the given OutputStream.

Parameters:
os - the OutputStream to use for output.
See Also:
print(PrintWriter)

resolveAliases

public void resolveAliases()
                    throws MalformedAliasException,
                           UnresolvedAliasException,
                           NoSuchAttributeException
Before the DDS can be used all of the Aliases in the various AttributeTables must be resolved. This means that it is necessary to verify that each Alias references an Attribute that exists, and is not another Alias. This is accomplished by searching the DDS's variable's attribute holdings for Aliases Everytime an Alias is located, a new search begins to find the Attribute that the Alias is attemoting to reference.

This method recursively searchs through the passed BaseType parameter bt for Alias members of AttributeTables, and when they are found attempts to resolve them to a specific Attribute.

This method should be called ONLY after the entire DDS has been parsed and /or built using the DDS API.

This method should/must always be called prior to using a DDS!

This method manipulates the global (private) variable currentBT. This method manipulates the global (private) variable currentAT.

Throws:
MalformedAliasException
UnresolvedAliasException
NoSuchAttributeException

normalize

public static java.lang.String normalize(java.lang.String field)
The normalize method is used to normalize variable and attribute name strings prior to their comparison with the normalized tokens extracted from the variable and name fields in an Alias declaration.

The rule for this normalization is as follows:

Parameters:
field - The string to be normalized.
Returns:
The "normalized" string.

tokenizeAliasField

public static java.util.Vector tokenizeAliasField(java.lang.String field)
                                           throws MalformedAliasException
The tokenizeAliasFiled() method is used to tokenize the variable and the attribute fields in the alias declaration. It is required that these fields be normalized in the XML instance document. The rules for this normalization are as follows:

Parameters:
field - The string to be tokenized.
Returns:
The tokenized string.
Throws:
MalformedAliasException

printXML

public void printXML(java.io.PrintWriter pw)
Prints the peristent representation of the DDS as an XML document. This XML document is know as a DDX. The DDX can be parsed using the DDSXMLParser

Overrides:
printXML in class BaseType
Parameters:
pw - The PrintWriter to print to.

This class/method is associated with pre-release version of the DDX API. It is experimental and is subject to (significant) change.


printXML

public void printXML(java.io.PrintWriter pw,
                     java.lang.String pad,
                     boolean constrained)
Prints the peristent representation of the DDS as an XML document. This XML document is know as a DDX. The DDX can be parsed using the DDSXMLParser

Overrides:
printXML in class DConstructor
Parameters:
pw - The PrintWriter to print to.
pad - A String to print at the begining of each line. typically this is some white space.
constrained - A boolean that indcates if the this call should print the constrained version of the DDS. A value of true will cause the only the projected variables of the DDX to be printed .

This class/method is associated with pre-release version of the DDX API. It is experimental and is subject to (significant) change.


ingestDAS

public void ingestDAS(DAS das)
Takes the passed parameter das and attempts to incorporate it's contents into the Attributes of the DDS variables. If an Attribute in the DAS can't be associated with a variable in a logical manner then it is placed at the top level of the DDS. (Basically it becomes a toplevel attribute in the dataset)

Parameters:
das - The DAS to ingest.

This class/method is associated with pre-release version of the DDX API. It is experimental and is subject to (significant) change.


checkForAttributeNameConflict

public void checkForAttributeNameConflict()
                                   throws BadSemanticsException
Check for name conflicts. In the XML representation of the DDS it is syntactically possible for a variable container (Dconstructor) to possess an Attribute that has the same name as one of the container variable's member variables. That's a NO-NO!. Check for it here and throw a nice fat exception if we find it.

Throws:
BadSemanticsException

getDDSText

public java.lang.String getDDSText()
This a wrapper method for DDS.print().

Returns:
The output of DDS.print() as String
See Also:
print(PrintWriter)

getDDXText

public java.lang.String getDDXText()
This a wrapper method for DDS.printXML().

Returns:
The output of DDS.printXML() as String
See Also:
printXML(PrintWriter)

This class/method is associated with pre-release version of the DDX API. It is experimental and is subject to (significant) change.