Prev Up Next
Go backward to 4.4 Parts of the server you don't have to write
Go up to Top
Go forward to 6 Subclassing the data types

5 Getting ready to write your components

The three object handlers are normally implemented in three separate programs. Each program has a main() function that looks like:

 
#include <iostream>
#include <string>

#include "DDS.h"
#include "cgi_util.h"
#include "DODSFilter.h"

extern void read_descriptors(DDS &dds, const string &filename)
    throw  (Error);

int 
main(int argc, char *argv[])
{
    DDS dds;
    DODSFilter df(argc, argv);
       
    try {
        if (!df.OK()) {
            df.print_usage();
            return 1;
        }
        
        if (df.version()) {
            df.send_version_info();
            return 0;
        }

        // Read the netCDF file dataset descriptor in memory
        read_descriptors(dds,  df.get_dataset_name());
        df.read_ancillary_dds(dds);
        df.send_dds(dds, true);
    }

    catch (Error &e) {
        set_mime_text(cout, dods_error,
        df.get_cgi_version());

        e.print(cout);
        return 1;
    }

    return 0;
}

Most of the software is boilerplate. The first two lines of main() are shown here:

DS dds;
DODSFilter df(argc, argv);

These declare an instance of DDS, to be used a little later as well as an instance of DODSFilter. The latter is used to parse command line arguments fed to the program by the dispatch script. By using this class in concert with the dispatch script, you can assume that the correct options and arguments will be passed into your program. The instance of DODSFilter, df, contains accessors for all the switches that the dispatch script might use, so by passing argc and argv to its constructor, you're sure to parse them all.

try {
   if (!df.OK()) {
         df.print_usage();
         return 1
   }
   
   if (df.version()) {
         df.send_version_info();
         return 0;
   }

This code calls the DODSFilter invariant to check that the handler was invoked correctly. If a malformed request was made to the server, this will be flagged here and the server will return an error message describing how to submit a correctly formed URL. This also tests to see if the request is for version information. If so, the DODSFilter object prints the server's version number and the handler exits. Just about every server built with our code includes these lines verbatim.

  
   // Read the netCDF file dataset descriptor in memory

   read_descriptors(dds, df.get_dataset_name());
   df.read_ancillary_dds(dds);

   df.send_dds(dds, true);

These lines are the heart of the handler. Exactly what's going on here will be covered in more detail later. However, each of the three object handlers contains similar code that builds the object to returned as the response and then passes that object to the DODSFilter::send_dds, send_das or send_data method, depending on the type of object to be returned.

 
   catch (Error &e) {
       set_mime_text(cout, dods_error, df.get_cgi_version());
       e.print(cout);

       return 1;
   }

   return 0;

Rounding out the program is a catch block that picks up exceptions thrown by the any of DAP library code. The DAP library throws two types of exceptions, Error and InternalErr. The latter is a subclass of Error, so catching just Error will get everything. Note that you should also catch bad_alloc exceptions at this level (the library does not) unless you catch them inside the function or method that builds the DDS, DAS or DataDDS. If e is an InternalErr, then when it prints, you'll see information about the file and line number where the problem was detected. Regular Error objects print something that's more useful to users. By calling the set_mime_text function (see the file cgi_util.cc) you're sure that the error message will be returned to the client in a form that both web browsers and more sophisticated clients can use.


James Gallagher <jgallagher@gso.uri.edu>, 2006-08-17, Revision: 14349

Prev Up Next