With distributed applications, especially with distributed objects, the distinction between a client and server is not determined so much by a program on a specific machine as it is by a state the program is currently in. Thus a program can be both a client and a server, depending on its purposes. For example, it is possible that, when a client object uses a function that has another object as an input parameter (our add( ) function, for example), the input could easily be an object that is local to the client. When the server is executing the add( ) function, it needs a way to transparently access the input object that is now remote to the server (but local to the client).
A server accesses client objects by linking in the client stub in addition to the server stub. When an object is remote to the server, information in the binding from a client is used automatically by the server stub during unmarshalling to create an object reference and make remote calls back to the client to access the object there. Server code itself does not have to do any special calls.
The following figure illustrates a brief review of all the code modules a typical server needs. The server stub for each interface and initialization code are required to access DCE's distributed environment. Each interface requires a manager class, manager code, and static member functions to implement them. Each interface with input object parameters should include the client stub in order for the server stub to access client-local objects.
Servers Need the Client Stub to Access Client-Local Objects
Making this work includes one other step besides linking in a client stub. If there are any static member functions in the interface class, linking together a client and server stub will produce a C++ compiler error due to a name conflict in the server and client stub versions of the function. You use the cxx_static attribute in an ACF to rename the server's local version of the static functions. An example of such an ACF is as follows:
/* FILE NAME: matrix.acf */
interface Matrix
{
/* include files generated into the server stub */
[sstub] include
"matrix_mgr", "staticfunc";
/* createMatrix should be mapped as a creator function. The */
/* argument represents the class that implements the
interface.*/
[cxx_new(MatrixMgr)] createMatrix();
/* newMatrix should be mapped as a static member function. */
[cxx_static(LocalMatrix)] newMatrix();
}
The LocalMatrix argument to the cxx_static attribute is the name for this server's local implementation of the function, and the newMatrix name refers to the remote (in this case, the client stub) function.
The include statement is needed with the sstub attribute to include header files that contain declarations needed by the server stub only. In this example, the matrix_mgr.h file contains the server's manager class declaration, and the staticfunc.h file contains the declaration of the renamed static function, LocalMatrix. The staticfunc.h header file is as follows:
// FILE NAME: staticfunc.h
// This file declares the function(s) to call
// when invoking local versions of an interface's static functions.
// The
prototype signatures should match that of the remote versions.
idl_boolean LocalMatrix(idl_long_int, idl_long_int, Matrix **m);
Note: Servers will work without including the client stub and renaming the local version of the static functions. However, if a client ever uses a member function with an object parameter that is remote to the server, a runtime error occurs. If this happens, the server raises an exception (rpc_x_no_client_stub) to propagate back to the client that indicates the client stub is not included in the server.