PreviousNext

Location Transparency of Local and Remote Objects

The previous topics showed separate cases of how to create objects that are either remote or local. However, many applications use a mixture of remote and local objects. For example, a presentation application can link in a video clip from another system (remote), or it can embed a copy of the video clip into the presentation itself (local). After the objects are created, we want the distinction to be as transparent as possible to simplify application code. In DCE, you can also intermix local and remote objects in function calls without needing to keep track of which is which.

To prepare your application to handle both local and remote objects simultaneously, do the following development steps:

1. Use the cxx_static ACF attribute to rename local versions of static functions.

2. Use the IDL compiler to produce both the client and server stub code.

3. Link into your client the client stub, server stub, and local object implementation code.

To accomplish this, you develop the client as if you are producing both a client and a server simultaneously. The only real difference is that you do not need any server initialization code. This means that your application includes the idl-generated manager class header and server stub, and manager implementation code for each interface. (See the following figure.) A client uses the client stub to produce and use remote objects. The client uses the server code to produce and use client-local objects of the interface class. This makes more sense when you think about server development: the manager class and code implement distributed objects of the interface class that are local to the server, so it helps to think local implementation code rather than server implementation code when we use server stubs, manager classes, and manager code in a client.If your application fails to use the server stub, the exception rpc_x_no_server_stub is raised by the client if your application tries to use local objects.


Clients Use the Server Stub

The IDL compiler requires an ACF such as the following when a client uses both remote and local objects:

/* FILE NAME: matrix.acf */

interface Matrix
{
/* include files generated into the server stub */
[sstub] include "matrix_mgr", "staticfunc";

/* createMatrix must be mapped as a creator member function. */
/* The argument MatrixMgr names the class that implements the */
/* interface for the server stub. */
[cxx_new(MatrixMgr)] createMatrix();

/* The "newMatrix" name represents the remote version of the */
/* function that is used by either the client application or */
/* the server stub. */
[cxx_static(LocalMatrix)] newMatrix();
}

[sstub] include
The include statement causes the IDL compiler to include header files in stubs. Data structures and definitions in code that are required by stubs need to be included in this way. This example applies the sstub attribute to specify the inclusion of matrix_mgr.h and staticfunc.h files in the server stub only. The matrix_mgr.h file contains the definition of the client-local manager class. This class defines the implementation of the interface and is derived from the interface class. The file staticfunc.h contains declarations of static member functions for the interface. In this example, there is only one static member function: LocalMatrix( ).

[cxx_new(MatrixMgr)] createMatrix( );
The cxx_new attribute specifies that a static member function of the interface is an object creator function. An argument (in this case, MatrixMgr) is needed to name the manager class, the class derived from the interface class to implement local interface objects. For the client stub, the argument is ignored and the function createMatrix( ) is generated as a static member function. The client application uses this function to create a remote interface object. For the server stub (or, in this case, the client-local implementation), the MatrixMgr argument represents the manager class name defined in a header file previously specified in the ACF with the include statement. The application uses the new operator on the MatrixMgr class to create a local interface object.

[cxx_static(LocalMatrix)] newMatrix( );
The cxx_static attribute specifies the interface's static member functions. All static member functions need to have this attribute (unless you use the static keyword in the interface definition to specify the function as static). An argument is required to avoid name conflicts between the local and remote versions of the function when both client and server stubs are linked together in the same application. For the client stub, the argument is ignored and the client application calls newMatrix( ) for remote access to the interface. For the client-local (server) stub, the argument is used to name the function, and the application calls LocalMatrix( ) for local access to the interface.

The following example shows client code to create and use both remote and local objects from an interface class:

#include "matrix_mgr.h"
#include "printmatrix.h" // print( ) macro

void
main()
{
idl_long_int d1, d2, d3, d4;
Matrix *mremote, *mlocal, *mr, *ml;

d1 = 1; d2 = 2; d3 = 3; d4 = 4;

cout << "Creating dynamic objects:" << endl;

// Create a remote Matrix object on a server
mremote = Matrix::createMatrix(d1, d2, d3, d4);
cout << "mremote created:" << endl;
print(mremote);

// Create a local Matrix object in this program
mlocal = new MatrixMgr(d4, d3, d2, d1);
cout << "mlocal created:" << endl;
print(mlocal);

// Create another object from a local and remote one.
// Whether the new matrix is local or remote depends on whether
// the invoking object is local or remote.

// create another remote Matrix while accessing a local object
mremote->add(mlocal, &mr);
cout << "mr is remote. It's the sum of mremote and mlocal:" << endl; print(mr);

// create another local Matrix while accessing a remote object mlocal->add(mremote, &ml);
cout << "ml is local. It is the sum of mlocal and mremote:" << endl;
print(mr);

// Applications should ALWAYS delete remote dynamic objects when
// through, otherwise, the server will waste resources maintaining
// them.
delete mremote, mlocal, mr, ml;

cout << "Client exiting" << endl;

return;
}

Matrix *mremote, *mlocal, *mr, *ml;
Local and remote object references are both defined as pointers to the interface class. Depending on how an object is created, polymorphism causes the invocation of a client stub function for remote objects or the locally defined function for local objects.

mremote = Matrix::createMatrix(d1, d2, d3, d4);

mlocal = new MatrixMgr(d4, d3, d2, d1);
Clients call a static creator function to create a remote object on a server and use the C++ new operator to create a local object.

mremote->add(mlocal, &mr);
A client can use remote and local objects together. In this example, a local object (mlocal) is added to the invoking remote object (mremote) to create a new remote object (mr) that is the sum of the two.

mlocal->add(mremote, &ml);
In this example, a remote object (mremote) is added to the invoking local object (mlocal) to create a new local object (ml). Whether the resulting object is local or remote depends on the invoking object.

delete mremote, mlocal, mr, ml;
Clients use the C++ delete operator to delete both local and remote objects. If a client does not delete local objects prior to exiting, no real harm is done since all the memory for the application is released. However, clients should always delete remote objects when finished with them because the servers maintain them even after the client has exited.