NonStop Software

Developing Client Applications

Previous Topic | Next Topic | Contents | Index
Getting Started Guide | Administration Guide | Reference Guide

Subtopics

Initializing the Object Request Broker (ORB)
Obtaining Object References
Narrowing Object References
Invoking Methods
Handling Exceptions
Releasing Object References
Unavailable System Calls

This section provides an overview of the basic topics required for developing client applications using NonStop DOM. After reading this section, you will be able to develop a client application that performs some or all of the following:

  1. Initializes the Object Request Broker (ORB)
  2. Obtains object reference
  3. Narrows the reference
  4. Invokes methods on objects
  5. Handles exceptions
  6. Releases object references

Additional information on these topics is covered in later sections.

We use the client side of the Stock example program introduced earlier in this guide. The workings of the client program are examined in detail here to help you understand general NonStop DOM client application development.

Initializing the Object Request Broker (ORB)

Prior to using any of the NonStop DOM methods or invoking any methods on user defined objects, a client program must initialize the ORB object. The following code shows how the initialization is done:

ORB Initialization
int main(int argc, char *argv[])
{
  // Initialize the ORB
  CORBA::ORB_ptr orb = CORBA::ORB_init(argc, argv);

The values argc and argv passed to ORB_init( ) describe the command-line arguments passed to the main program. These are the count of arguments and a pointer to a list of argument strings, respectively. The ORB_init( ) method interprets some command-line arguments. In particular, the -ORBprofile argument specifies the execution profile used by this program. ORB_init( ) uses the profile name to retrieve profile information from the NonStop DOM configuration database.

A successful call to ORB_init( ) returns an object reference for the ORB. The return type is a CORBA::ORB_ptr. This object reference is used later to invoke methods defined for the ORB object.

If necessary, ORB_init( ) can be invoked more than once. Typically, this is necessary only to obtain the ORB object reference in modules other than the main program. As in the main program, the ORB object reference is used to invoke methods defined for the ORB object.

Obtaining Object References

To make requests on an object, the client must obtain an object reference for the object. The object reference encapsulates all the information the ORB needs to reach the object and invoke methods on it. See Object References for a full discussion of object references.

There are two ways for a client to get an object reference:

Reading an Object Reference From a File

A server program that hosts the object can create an object reference and write it to a file. Later, the client program can read the object reference and use it.

Here is an example of code to read the object reference from a file and convert it to a usable format:
Read Object Reference From a File
// Read IOR from file, convert it to an object reference
CORBA::Object_ptr CORBAObject;

FILE *IORFile = fopen("ior.txt", "r" );

char * IORString = new char[1000];
fread( IORString, 1, 1000, IORFile );

CORBAObject = orb->string_to_object( IORString );
delete [] IORString;

Obtaining an Object Reference From a Method Invocation

An object reference can be returned as an output of a method invocation. The Naming Service is often used for this purpose. An object reference previously stored in the Naming Service can be retrieved by invoking the resolve( ) method. A server hosting an object stores the object reference in the Naming Service so that it can be retrieved by client programs. Of course, the client program must first have the object reference for the Naming Service. This is obtained in a special way by invoking the resolve_initial_references( ) method.

Here is an example of code to obtain an object reference from the Naming Service:

Get Root Context for Naming Service
CORBA::Object_ptr CORBAObject;
CORBAObject = orb->resolve_initial_references("NameService");
RootNameContext = CosNaming::NamingContext::_narrow(CORBAObject);

// Find the Stock object
name.length(2);
name[0].id = "NSDOM-Samples";
name[0].kind = "";
name[1].id = "StockObject";
name[1].kind = "";

TRY
{
    CORBAObject = RootNameContext->resolve(name);
}
CATCH(CORBA::SystemException, exception)
{
    cout << "Error: Exception during resolve: " << exception << endl;
    return 1;
}
ALSO_CATCH(CORBA::UserException, exception)
{
  cout << "Error: Unable to find StockObject"
    << " in Naming Service." << endl
    << "   " << exception << endl;
   return 1;
}
END_CATCH

Narrowing Object References

To invoke methods on an object, an object reference must be of the correct type. The two techniques discussed for obtaining object references both produce an object reference of type CORBA::Object, but you need an object of type Stock. Assuming the object reference actually refers to a Stock object, you can use the _narrow( ) method to obtain a correctly typed reference. The _narrow( ) method is produced by the IDL compiler when the IDL file describing the object interface is compiled.

Here is code showing how the _narrow( ) operation is used.

The Narrowing Operation
Stock_var aStockObject;

// Perform a narrow operation to get a stock object reference
TRY
{
    aStockObject = Stock::_narrow(CORBAObject);
}
CATCH (CORBA::Exception, exception)
{
    cout << "Unexpected exception during narrow operation." << endl
     << exception
     << endl;
    exit(EXIT_FAILURE);
}
END_CATCH

Invoking Methods

Once an object reference of the correct type is available, a client can invoke methods on the object. Any of the methods defined in the interface definition for the object can be invoked. Methods are invoked using the usual C++ method-invocation syntax. Parameters for the method are those specified in the method declaration. Here is an example method invocation using the Stock object:

CORBA::Double Last, High, Low;
CORBA::ULong Volume;
TRY
{
    aStockObject->quote("CPQ", Last, High, Low, Volume );
}
CATCH (CORBA::Exception, exception)
{
    cout << "Unexpected system exception during quote operation." << endl
         << exception
         << endl;
    return 1;
}
END_CATCH

In this example, the quote( ) method is invoked. The method declaration in the IDL appears as:

void quote( in string Symbol, out double Last, out double High,
            out double Low, out unsigned long Volume )
            raises( operationFailed );

The first parameter is an input parameter of type string. In C++ the corresponding type is a pointer to a string. The remaining parameters are output parameters; that is, the values are produced by the quote( ) method. Three of the parameters are of type double and one is of type unsigned long . In C++ the corresponding types are CORBA::Double and CORBA::ULong.

Handling Exceptions

When a client application program invokes methods, it must be prepared to handle exceptions. Generally, an exception indicates that an unexpected or unusual condition occurred during method invocation. There are two categories of exceptions: system exceptions and user exceptions. System exceptions are raised when there is an error during request processing. User exceptions are raised by method implementations and are used to communicate an usual condition back to the requester.

Exceptions can occur on any method invocation on a CORBA object, so it is good programming practice to check rigorously for them. Undetected exceptions can lead to incorrect program behavior that is difficult to troubleshoot. When an exception is detected, take appropriate steps to ensure correct processing. Depending on the application program used, one might reissue the request, take an alternative processing path, log an error, or abnormally exit the program.

Environment Exceptions

When working with NonStop DOM applications, it is recommended that you use environment exceptions to handle the exceptions in all multi-threaded, scalable applications. Environment exceptions are provided with NonStop DOM in a CORBA environment class.

To use the environment exceptions, set the NSD_ENV switch in your project Makefile. You do this by adding a line to your Makefile immediatly above the include macros.mk line so that the code reads as follows:

NSD_ENV=1
include macros.mk

Setting NSD_ENV causes the IDL compiler to generate stubs and skeletons that make use of the environment exceptions. When you use environment exceptions, the IDL compiler generates method signatures which include an environment variable as the final parameter. Generally, this is provided automatically as a default parameter.

The programming pattern for using these macros is illustrated here:
Using Exception-Handling Macros
TRY
{
    // user code including NonStop DOM method invocation
}
CATCH (<exception-type>, <variable>)
{
    <exception-type>
}
END_CATCH

The exception-type is one of the following:

Table 1. Types of Exceptions
exception-type usage
CORBA::Exception catches an system or user exception
CORBA::SystemException catches any system exception
CORBA::specific-exception catches a specific system exception
CORBA::UserException catches any user exception
user-class::user-exception catches a specific user exception

To check for more than one exception, use the ALSO_CATCH clause. This follows the first CATCH and must precede the END_CATCH clause. As many of these as necessary can be used. They are evaluated in order.
Catching More Than One Exception
TRY
{
    // user code including NonStop DOM method invocation  
}
CATCH (exception-type, <variable>)
{
    <exception-type>
}
ALSO_CATCH (exception-type, <variable>)
{
    <exception-type>
}
END_CATCH

There is also a CATCH_ALL macro that can be used to catch an exception of any type.
Catching All Exceptions
TRY
{
    // user code including NonStop DOM method invocation  
}
CATCH_ALL
{
    <exception-type>
}
END_CATCH

Releasing Object References

When a client application program is finished using an object reference, it should release it. Releasing the object reference allows the ORB to release locally allocated memory for the object reference. Note that "release" does not affect the actual object residing in the server.

Releasing The Object
//  Release the object (locally)
CORBA::release(aStockObject);

Unavailable System Calls

A client is free to make all Guardian and OSS calls, except for the following:

Such calls would interfere with the NonStop DOM runtime.


Previous Topic | Next Topic | Contents | Top
Getting Started Guide | Administration Guide | Reference Guide
Bibliography | Glossary | Index
© Tandem, a division of Compaq. All rights reserved. Legal notices.