Application Building
Todo:
Make sure this document is up to date and maybe add a sequence diagram.

While not GNSS-related, the gnsstk provides a set of frameworks to reduce the amount of effort required when writing applications.

The classes used for quickly implementing applications are:

  • BasicFramework for simple applications with no repetitive processing.
  • LoopedFramework for applications with repetetive processing.
  • CommandOption which is the parent class for a myriad of specialized command-line option processing classes.

Overview

Using the application frameworks is pretty consistent across all applications (which of course is the intent). An application will define a class that derives from one of the frameworks, and overrides the methods of the framework class that are appropriate for the application. The implementation of the main function is very similar from application to application, with only the application class name changing, in general.

The structure of applications using these frameworks follows the following formula:

class MyApp : public gnsstk::BasicFramework
{
public:
MyApp(const std::string& appName);
virtual ~MyApp();
void process() override;
};
int main(int argc, char *argv[])
{
try
{
MyApp app(argv[0]);
if (app.initialize(argc, argv))
{
app.run();
}
return app.exitCode;
}
catch (gnsstk::Exception& e)
{
cerr << e << endl;
}
catch (std::exception& e)
{
cerr << e.what() << endl;
}
catch (...)
{
cerr << "Caught unknown exception" << endl;
}
}

BasicFramework Usage

When you need to implement an application that performs a single task before exiting (timeconvert is a good example of this), BasicFramework is probably the ideal framework class for you to use.

The flow of execution for applications derived from the BasicFramework class is as follows (indentation levels indicate the call stack):

  1. main()
    1. Constructor
    2. initialize() (often overridden)
    3. run() (never overridden)
      1. completeProcessing() (rarely overridden)
        1. additionalSetup() (often overridden, empty by default)
        2. spinUp() (often overridden, empty by default)
        3. process() (often overridden, empty by default)
      2. shutDown() (sometimes overridden)

The functions/methods of an application class perform functions as follows:

  • main() instantiates the application class and executes the code.
  • Constructor does all the usual things C++ constructors do, including calling the parent's class' constructor and initializing the command-line option objects.
  • initialize() processes the command-line options.
  • run() calls the completeProcessing() method in a try/catch block, and calls shutDown().
  • completeProcessing() calls additionalSetup(), spinUp() and process() in that order. Sometimes it may be overridden for additional processing (see LoopedFramework Usage), but this is fairly rare and typically is only done in specialized frameworks.
  • additionalSetup() is a method intended to be used when additional tasks are needed to be done prior to the main execution that depend on the completion of tasks in the initialize() method.
  • spinUp() is a method intended to be used when additional tasks are needed to be done prior to the main execution that depend on the completion of tasks in both the initialize() method and the additionalSetup() method.
  • process() is where the meat of the application is, i.e. where the primary application work takes place.
  • shutDown() is called at the end of successful (no exceptions thrown) program execution. It is meant to be used to allow an application to clean up after itself, like closing files, network connections, etc.

Why are there so many methods defined? The main reason is to allow further differentiation when specializing frameworks. That is, there are derived classes that provide further frameworks capabilities where initialization must occur in a very specific order, but the subclasses need to be able to override specific behaviors.

Exit Codes

The BasicFramework class defines a data member named exitCode. This is intended to be used as the return value for main() (see the example in Overview). It is initialized to 0, which indicates successful completion of applications. Any non-zero return from main will be interpreted by the shell as a failed execution. While BasicFramework will set exitCode to an error code for exceptions caught within run() or command-line processing errors within initialize(), implementers should remember two things:

  1. The implementer should set the exitCode variable to an appropriate value when terminating on failure for any condition not handled as described above.
  2. The implementer must explicitly return the value of exitCode in their main() function. This is not handled automatically by the frameworks.

The following generic exit codes are defined within BasicFramework:

Other exit codes can be defined as needed on a per-application basis.

LoopedFramework Usage

LoopedFramework is identical to BasicFramework with the following exceptions:

  • a boolean flag named timeToDie is added to control loop execution.
  • the process() method is called by completeProcessing() continuously until the timeToDie flag is set to true.

LoopedFramework is meant to be used when executing a set of statements repeatedly. Derived classes should set timeToDie to true whenever an appropriate termination condition has been met.

Command-Line Options

Command-line option processing used by the application frameworks involves the instantiation of objects derived from the CommandOption class. Usually this is done inside the application class constructor, however there may be occassions where the command option object is instantiated dynamically based on some conditional (typically only done in other frameworks). The CommandOption class and children do not have a default constructor, which is the primary reason for instantiating these objects in the application constructor.

The CommandOption classes in most cases will let you specify a short command-line option (e.g. 'h' becomes -h on the command line), a long command-line option (e.g. "help" becomes –help on the command line), a description of the command line option to be printed when help is requested, and a flag indicating whether the command-line argument is required or not. The CommandOption class has several other constructor parameters but using that class directly rather than one of the child classes is pretty much unheard of.

Really basic command-line option classes that are never directly used:

Command-line options that take an argument of some sort, usually with format checking of that argument:

Class Description Example
NoArg Boolean or with count CommandOption1.cpp
WithAnyArg No arg format checking CommandOption1.cpp
WithStringArg Alpha chars only in arg
WithNumberArg +/- integer arg CommandOption2.cpp
WithDecimalArg decimal argument CommandOption2.cpp
WithTimeArg multi-format time arg
WithSimpleTimeArg pre-defined multi-format time arg
WithCommonTimeArg formatted time arg CommandOption2.cpp
WithPositionArg formatted position arg
Rest args with no option CommandOption1.cpp

Classes for defining relationships between real command-line arguments:

Class Example Requires
NOf CommandOption3.cpp exactly N uses of x, y, z
OneOf CommandOption3.cpp at least one usage of x, y, z
AllOf CommandOption4.cpp all or none of x, y, z must be used
Mutex CommandOption4.cpp ONLY one of x, y, or z
Dependent CommandOption4.cpp e.g. if x is used, then y must be used

Classes for implementing logical checks in conjunction (i.e. as one of the "options") in the above classes:

Class Example Virtually set if
GroupOr CommandOption5.cpp any of x, y or z are used
GroupAnd all of x, y and z are used

Help options. These are handled specially by BasicFramework such that

  • CommandOptionHelp is the parent class for all help requested on the command-line. The use (on the command-line) of any instances of objects derived from this class will result in the frameworks terminating after the initialize() method completes.
  • CommandOptionHelpUsage is the command-line option help, that prints out the standard usage information (in conjunction with -h or –help arguments). An instance of this is already used in BasicFramework so you shouldn't ever need to directly use this class.
  • CommandOptionHelpSimple provides a very basic help feature that prints a pre-defined message. If you want to add a command-line option that prints out a simple text message and exits without further processing, this just might be the class for you.

BasicFramework will exit after printing the appropriate help information when any of the above command-line option types are requested by the user.

The arguments to the command-line arguments (e.g. for "-n 5", "5" is the argument) are available as a vector of strings (where each value in the vector corresponds to one use of the command-line argument) via the getValue() method. In most cases you will need to convert the strings to the appropriate data type yourself (time being an exception).

As an example, if a user specifies "-n 5 -n 7 -n 11", getValue() will return an array of the strings "5","7,"11". A common method for handling cases where only one argument is allowed is to use the vector [] operator like "someOpt.getValue()[0]".

A very common situation you will have is to limit the number of times a command-line argument can be used. This is usually done by calling the setMaxCount() method on the CommandOption-derived class in the application's constructor. See the example codes and CommandOption documentation for more details.

gnsstk::Exception::what
std::string what() const
Dump to a string.
Definition: Exception.cpp:193
gnsstk::BasicFramework::EXCEPTION_ERROR
static const int EXCEPTION_ERROR
Definition: BasicFramework.hpp:392
gnsstk::Exception
Definition: Exception.hpp:151
gnsstk::BasicFramework
Definition: BasicFramework.hpp:387
main
int main(int argc, char *argv[])
Definition: BasicFrameworkHelp_T.cpp:144


gnsstk
Author(s):
autogenerated on Wed Oct 25 2023 02:40:43