The DAP defines a data type hierarchy as the core of its data model. This
collection of data types includes scalar, vector and constructor types. Most
of the types are available in all modern programming languages with the
exceptions being Url, Sequence and Grid. In the DAP
library, the class BaseType is the root of the data type tree.
The DAP supports the common scalar data types such as Byte, 16- and 32-bit
signed and unsigned integers, and 32- and 64-bit floating point numbers. The
DAP also supports Strings and Urls as basic scalar types. The DAP includes
Arrays of unlimited size and dimensionality. The DAP also supports three
type-constructors: Structure, Sequence and Grid. A
Structure on the DAP mimics a struct in C. A Sequence is a
table-like data structure inherited from the JGOFS data system. It can be
used to hold information that might be stored in relational databases or
tables, either flat or hierarchical. The JGOFS, FreeForm and HDF servers all
use the Sequence data type. Lastly, the Grid data type is used to
bind an array to a group of map vectors, single dimension arrays that
provide non-integral values for the indices of the array. The most typical
use of a Grid is to provide latitude and longitude registration for some
georeferenced array data (e.g., a projected satellite image). The DAP does
not have a pointer data type, but in some cases the Url data type can
be used as a pointer to variables between files. More information about the
DAP's data type
hierarchy
is given in the Programmer's Guide.
In the remainder of this tutorial the Matlab 5 OPeNDAP server will be used as an example. It is a real, non-trivial, server that you can download and run, if you choose.
The Matlab 5 server makes a good example for this tutorial because the Matlab 5 data model is very limited. Matlab 5 supports scalars, vectors and matrices. For basic types it supports only floating point numbers and strings.
In the Matlab 5 server, we treat scalar strings as attributes and all other types as variables.
When you start building a DAP server, the first thing you must do is create a collection of data type subclasses. That is, each of the leaf classes in the preceding class diagram must be subclassed by your server. This is pretty easy since a good bit of the work is rote.
First we'll illustrate the parts that are mechanical. Here's an example from the Matlab server. The class is the Byte class. In the case of the matlab server, this class doesn't do anything beyond the bare minimum, so it's a good starting point:
Byte *
NewByte(const string &n)
{
return new MATByte(n);
}
MATByte::MATByte(const string &n) : Byte(n)
{
}
BaseType *
MATByte::ptr_duplicate()
{
return new MATByte(*this);
}
bool
MATByte::read(const string &)
{
throw InternalErr(__FILE__, __LINE__, "Unimplemented read method
called.");
}
To create a child of any of the data type leaf classes, you must define three
methods and one function. Let's talk about the function first. The function
NewByte is what Meyers[1] calls a virtual
constructor. It's similar to a low-budget factory class ("low-budget"
because it's not a class). This function is used at various places in the DAP
library when it need to create instances of Byte without knowing in
advance the dynamic type of the object that actually will be created. If all
this sounds a little weird, just remember that your Byte, Int16,
..., Grid classes -- whatever they may be called -- must all contain
an implementation of this function and each should all return a pointer to an
instance of the apropriate child class. These functions will be used by the
library to create instance of hte classes you have defined when writing your
server. In this case of the example Matlab server, it's an instance of the
MATByte class. If you look in the files for the Matlab server, you'll
see that the function NewGrid returns a pointer to a new MATGrid,
and so on.
Second, a constructor must be implemented and should take the name of the variable as its sole argument.
Third, your child classes should also define the ptr_duplicate()
method. This method returns a pointer to a new instance of an object in the
same class. Occasionally, in the DAP library, objects are declared with
pointers specified as BaseType *. If the new operator was used to
copy such an object, the copied object would be an instance of BaseType (the
static type of the object) not the type of the thing referenced (the dynamic
type)2. By using the ptr_duplicate() method the DAP
library is sure that when it copies an object, it's getting an instance of
the subclass defined by your server.
Finally, each of the child classes must provide an implementation of the
read method. This method is called by code in the DAP library to read
values from the data set. It will be explained in more detail when we get to
building DataDDS responses. For now, it's enough to know that if a particular
server has no use for a given data type (it happens that the Matlab server
will never need to create an instance of Byte, because Matlab 5 files can
only store float64 matrices) this method should throw an InternalErr object.