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:
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.
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:
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.
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:
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 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;
|
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:
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
|
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.
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
|
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.
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.
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:
TRY
{
// user code including NonStop DOM method invocation
}
CATCH (<exception-type>, <variable>)
{
<exception-type>
}
END_CATCH
|
The exception-type is one of the following:
| 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.
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.
TRY
{
// user code including NonStop DOM method invocation
}
CATCH_ALL
{
<exception-type>
}
END_CATCH
|
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.
// Release the object (locally) CORBA::release(aStockObject); |
A client is free to make all Guardian and OSS calls, except for the following:
AWAITIO or AWAITIOX with -1 as a file parameter.Such calls would interfere with the NonStop DOM runtime.