Jump to content

Distributed SOM (DSOM): Difference between revisions

From EDM2
Line 645: Line 645:


==Basic Client Programming==
==Basic Client Programming==
        DSOM Object Manager
For the most part, client programming in DSOM is exactly the same as client programming in SOM, since DSOM transparently hides the fact that an object is remote when the client accesses the object.
        Initializing a client program
 
        Exiting a client program
However, a client application writer also needs to know how to create, locate, use, save, and destroy remote objects. (This is not done using the usual SOM bindings.) The DSOM run-time environment provides these services to client programs primarily through the DSOM Object Manager. These run-time services will be detailed in this section. Examples of how an application developer uses these services are provided throughout the section.
        Creating remote objects
 
            Creating an object in an arbitrary server
===DSOM Object Manager===
            Proxy objects
DSOM defines a DSOM Object Manager, which provides services needed by clients to create, find and use objects in the DSOM run-time environment.
            Servers and server objects
 
            Creating an object in a specific server
The DSOM Object Manager is derived from an abstract, generic "object manager" class, called ObjectMgr. This abstract ObjectMgr class defines a basic set of methods that support object creation, location (with implicit activation), and destruction.
            Inquiring about a remote object's implementation  
 
        Destroying remote objects
As an abstract class, ObjectMgr defines only an interface; there is no implementation associated with ObjectMgr. Consequently, an application should not create instances of the ObjectMgr class.
            Destroying objects via a proxy
 
            Destroying objects via the DSOM Object Manager
An abstract Object Manager class was defined under the expectation that applications will often need simultaneous access to objects implemented and controlled by a variety of object systems. Such object systems may include other ORBs (in addition to DSOM), persistent object managers, object-oriented databases, and so forth. It is likely that each object system will provide the same sort of basic services for object creation, location, and activation, but each using a different interface.
            Destroying objects via a server object  
 
        Creating remote objects using user-defined metaclasses
Thus, the ObjectMgr abstract class defines a simple and "universal" interface that can be mapped to any object system. The application would only have to understand a single, common ObjectMgr interface. Under this scheme, specific object managers are defined by subclassing the ObjectMgr class and overriding the ObjectMgr methods to map them into the object system-specific programming interfaces.
        Saving and restoring references to objects
 
            Finding existing objects  
DSOM's Object Manager, SOMDObjectMgr, is defined as a specific class of ObjectMgr. It defines methods for:
        Finding server objects
 
        Invoking methods on remote objects
*Finding servers that implement particular kinds of objects
            Determining memory allocation and ownership  
*Creating objects in servers
        Passing object references in method calls
*Obtaining object identifiers (string IDs)
        Memory management
*Finding objects, given their identifiers
            Memory management for method parameters
*Releasing and destroying objects
            The CORBA policy for parameter memory management
 
            The 'somdReleaseResources' method and object-owned parameters  
These functions will be discussed in the remainder of this section.
        Writing clients that are also servers
 
        Compiling and linking clients  
;Note: The OMG has standardized an "object lifecycle" service, which includes support for creating and destroying distributed objects. The DSOM Object Manager may be augmented in the future with an OMG-compliant lifecycle service.
 
 
===Initializing a client program===
A client application must declare and initialize the DSOM run time before attempting to create or access a remote object. The SOMD_Init procedure initializes all of the DSOM run time, including the SOMDObjectMgr object. The global variable, SOMD_ObjectMgr is initialized to point to the local DSOM Object Manager.
 
A client application must also initialize all application classes used by the program. For each class, the corresponding <className>NewClass call should be made.
 
Note: In non-distributed SOM programs, the <className>New macro (and the new operator provided for each class by the SOM C++ bindings) implicitly calls the procedure <className>NewClass when creating a new object. This is not currently possible in DSOM because, when creating remote objects, DSOM uses a generic method that is not class-specific.
 
 
This was shown in the "Stack" example in section 6.2. In a similar example of an application that uses "Car" and "Driver" objects, the initialization code might look like this:
<PRE>
#include <somd.h>    /* needed by all clients */
#include <Car.h>    /* needed to access remote Car */
#include <Driver.h>  /* needed to access remote Driver */
 
main()
{
    Environment ev; /* ev used for error passing */
    SOM_InitEnvironment(&ev);
 
    /* Do DSOM initialization */
    SOMD_Init(&ev);
 
    /* Initialize application classes */
    CarNewClass(Car_MajorVersion, Car_MinorVersion);
    DriverNewClass(Driver_MajorVersion, Driver_MinorVersion);
    ...
}
</PRE>
 
As shown, client programs should include the "somd.h" file (or, for C++ programs, the "somd.xh" file) in order to define the DSOM run#time interfaces.
 
Note also that, since Environments are used for passing error results between a method and its caller, an Environment variable (ev) must be declared and initialized for this purpose.
 
The calls to "CarNewClass" and "DriverNewClass" are required if the client will be creating or accessing Cars and Drivers. The procedures "CarNewClass" and "DriverNewClass" create class objects for the classes "Car" and "Driver". When a DSOM Object Manager method like somdNewObject is invoked to create a "Car", it expects the "Car" class object to exist. If the class does not yet exist, the "ClassNotFound" exception will be returned.
 
===Exiting a client program===
At the end of a client program, the SOMD_Uninit procedure must be called to free DSOM run-time objects, and to release system resources such as semaphores, shared memory segments, and so on. SOMD_Uninit should be called even if the client program terminates unsuccessfully; otherwise, system resources will not be released.
 
For example, the exit code in the client program might look like this:
<PRE>
    ...
    SOMD_Uninit(&e);
    SOM_UninitEnvironment(&e);
}
</PRE>
Note also the SOM_UninitEnvironment call, which frees any memory associated with the specified Environment structure.
 
;Note: When a Windows DSOM client receives a WM-QUIT message while processing a remote method invocation, DSOM will clean up and terminate the client without returning to the client's WinProc or WinMain.
 
 
===Creating remote objects===
Distributed objects can be created in several different ways in DSOM.
*The client can create an object on any server that implements that class of object.
*The client can find a specific server upon which to create an object.
*A server can create an object and register a reference to the object in some well-known directory. (An object reference contains information that reliably identifies a particular object.)
 
The first two cases are discussed immediately below. The last case is discussed near the end of this section.
====Creating an object in an arbitrary server====
Following is an example of how to create a new remote object in the case where the client does not care in which server the object is created. In this situation, the client defers these decisions to the DSOM Object Manager (SOMD_ObjectMgr) by using the somdNewObject method call, which has this IDL definition:
 
<PRE>
  // (from file om.idl)
 
 
  SOMObject somdNewObject(in Identifier objclass, in string hints);
 
  // Returns a new object of the named class.  This is a "basic"
  // creation method, where the decisions about where and how to
  // create the object are mostly left up to the Object Manager.
  // However, the Object Manager may optionally define creation
  // "hints" which the client may specify in this call.
</PRE>
 
 
Here is the example of how a remote "Car" would be created using somdNewObject:
<PRE>
#include <somd.h>
#include <Car.h>
 
main()
{
    Environment ev;
    Car car;
 
    SOM_InitEnvironment(&ev);
    SOMD_Init(&ev);
 
    /* create the class object */
    CarNewClass(Car_MajorVersion, Car_MinorVersion);
 
    /* create a Car object on some server, let the
      Object Manager choose which one */
    car = _somdNewObject(SOMD_ObjectMgr, &ev, "Car", "");
    ...
}
</PRE>
 
The main argument to the somdNewObject method call is a string specifying the name of the class of the desired object. The last argument is a string that may contain "hints" for the Object Manager when choosing a server. In this example, the client is providing no hints. (Currently, the DSOM Object Manager simply passes the hints to the server object in a somdCreateObj call.)
====Proxy objects====
As far as the client program is concerned, when a remote object is created, a pointer to the object is returned. However, what is actually returned is a pointer to a proxy object, which is a local representative for the remote target object.
 
Proxies are responsible for ensuring that operations invoked on it get forwarded to the "real" target object that it represents. The DSOM run time creates proxy objects automatically, wherever an object is returned as a result of some remote operation. The client program will always have a proxy for each remote target object on which it operates. Proxies are described further in the sections entitled "DSOM as a CORBA-compliant Object Request Broker" and "Advanced Topics".
 
In the example above, a pointer to a "Car" proxy is returned and put in the variable "car". Any subsequent methods invoked on "car" will be forwarded and executed on the corresponding remote "Car" object.
 
Proxy objects inherit behavior from the SOMDClientProxy class.
====Servers and server objects====
In DSOM, the process that manages a target object is called the object's server. Servers are implemented as programs that use SOM classes. The example above placed no constraints on the DSOM Object Manager as to which server should create the remote "Car" object. However, if the client desires more control over distribution of objects, the DSOM Object Manager provides methods for finding specific servers.
 
Server implementations are registered with DSOM in an Implementation Repository. Server implementations are described by a unique ID, a unique (user-friendly) name, the program name that implements the server, the classes that are implemented by the server, the machine on which the server is located, whether the server is multi-threaded, and so forth. (See section 6.6 for more information on registering server implementations.) A client can ask the DSOM Object Manager to find a particular server:
 
*By name
*By ID
*By a class it supports
 
When a client asks for a "server", it is given (a proxy to) a server object that provides interfaces for managing the objects in the server. There is one server object per server process. All server objects are instances of the SOMDServer class, or its subclasses. The default method provided by SOMDServer for creating objects is:
<PRE>
  // (from file somdserv.idl)
 
  SOMObject somdCreateObj(in Identifier objclass, in string hints);
 
  // Creates an object of the specified class.  This method
  // may optionally define creation "hints" which the client
  // may specify in this call.  (Hints are ignored by default.)
</PRE>
 
Section 6.4 explains how to create application-specific server objects, derived from SOMDServer, which override SOMDServer methods and introduce their own methods for object management.
====Creating an object in a specific server====
The following example demonstrates how a client application creates a new object in a remote server chosen by the client. The DSOM Object Manager method somdFindServerByName is used to find and create a proxy to the server object for the server implementation named "myCarServer". The method somdCreateObj is then invoked on the server object to create the remote "Car". A proxy to the remote "Car" is returned. (The "Stack" client presented in the previous section used the same methods to create a remote "Stack".)
<PRE>
/* find a specific Car server */
    server =
      _somdFindServerByName(SOMD_ObjectMgr, &ev, "myCarSe          rver");
 
/* create a remote Car object on that server */
    car = _somdCreateObj(server, &ev, "Car", "");
    ...
}
</PRE>
 
;Note: If the specified server does not provide any implementation of the desired class, a NULL pointer will be returned and a "ClassNotFound" exception will be raised.
 
 
Three other methods can be invoked on the DSOM Object Manager to find server implementations: somdFindServer, somdFindServersByClass, and somdFindAnyServerByClass. The IDL declarations of these methods follow:
 
<PRE>
SOMDServer somdFindServer(in ImplId serverid);
 
sequence<SOMDServer> somdFindServersByClass(in Identifier objclass);
 
SOMDServer somdFindAnyServerByClass(in Identifier objclass);
</PRE>
 
The somdFindServer method is similar to the somdFindServerByName method, except that the server's implementation ID (of type ImplId) is used to identify the server instead of the server's user-friendly name (or "alias"). The implementation ID is a unique string generated by the Implementation Repository during server registration. (See section 6.6 for more details.)
 
The somdFindServersByClass method, given a class name, returns a sequence of all servers that support the given class. The client program may then choose which server to use, based on the server's name, program, or other implementation attributes (e.g., the server is multi-threaded). (See the topic below, "Inquiring about a remote object's implementation.")
 
Finally, the somdFindAnyServerByClass method simply selects any one of the server implementations registered in the Implementation Repository that supports the given class, and returns a server proxy for that server.
 
Once the server proxy is obtained, methods like somdCreateObj, shown in the example above, can be invoked upon it to create new objects.
 
====Inquiring about a remote object's implementation====
===Destroying remote objects===
====Destroying objects via a proxy====
====Destroying objects via the DSOM Object Manager====
====Destroying objects via a server object ====
===Creating remote objects using user-defined metaclasses===
===Saving and restoring references to objects===
====Finding existing objects====
===Finding server objects===
===Invoking methods on remote objects===
====Determining memory allocation and ownership====
===Passing object references in method calls===
===Memory management===
====Memory management for method parameters====
====The CORBA policy for parameter memory management====
====The 'somdReleaseResources' method and object-owned parameters====
===Writing clients that are also servers===
===Compiling and linking clients===
 
==Basic Server Programming==
==Basic Server Programming==
         Server run-time objects
         Server run-time objects

Revision as of 04:23, 9 May 2021

System Object Model Programming Guide
  1. About This Book
  2. Introduction to the SOMobjects Developer Toolkit
  3. Tutorial for Implementing SOM Classes
  4. Using SOM Classes in Client Programs
  5. SOM IDL and the SOM Compiler
  6. Implementing Classes in SOM
  7. Distributed SOM (DSOM)
  8. The SOM Interface Repository Framework
  9. The Metaclass Framework
  10. The Event Management Framework
  11. SOMobjects Error Codes
  12. SOM IDL Language Grammar
  13. Implementing Sockets Subclasses
  14. Glossary

Reprint Courtesy of International Business Machines Corporation, © International Business Machines Corporation

Note: The SOMobject Base Toolkit provides the capability for implementing Workstation Distributed System Object Module (DSOM) (distribution among processes on a single machine). Implementing an application that is distributed across a network of machines requires Workgroup DSOM, which is available only in the full-capability SOMobjects Developer Toolkit.

The following subjects are discussed in this section:

  • A Simple DSOM Example
  • Basic Client Programming
  • Basic Server Programming
  • Implementing Classes
  • Configuring DSOM Applications
  • Running DSOM Applications
  • DSOM as a CORBA-compliant Object Request Broker
  • Advanced Topics
  • Error Reporting and Troubleshooting
  • Limitations

What is Distributed SOM?

Whereas the power of SOM technology comes from the fact that SOM insulates the client of an object from the object's implementation, the power of DSOM lies in the fact that DSOM insulates the client of an object from the object's location.

Distributed SOM (or DSOM) provides a framework that allows application programs to access objects across address spaces. That is, application programs can access objects in other processes, even on different machines. Both the location and implementation of an object are hidden from a client, and the client accesses the object (by way of method calls) in the same manner regardless of its location.

DSOM currently supports two types of distribution:

  1. distribution among processes on the same machine (referred to as Workstation DSOM)
  2. and distribution among a network of machines (referred to as Workgroup DSOM).

DSOM runs on the AIX (Release 3.2.5 and above) and OS/2 (Release 2.0 and above) operating systems. A Workstation DSOM application can run on a machine in either environment using core capabilities of the SOMobjects system. Under the full capability SOMobjects Developer Toolkit, Workgroup DSOM supports distribution across local area networks comprised of both OS/2 and AIX systems. Future releases of DSOM may support large, enterprise-wide networks.

Support for TCP/IP and NewWare IPX/SPX is provided on AIX, OS/2, and Windows. NetBIOS support is provided for OS/2 and Windows. DSOM communications is extensible in that an application can provide its own transport (see Appendix C of the SOMobjects Base Toolkit Users Guide).

DSOM can be viewed in two ways:

  1. As a System Object Model extension that allows a program to invoke methods on SOM objects in other processes.
  2. As an Object Request Broker (ORB); that is, a standardized "transport" for distributed object interaction. In this respect, DSOM complies with the Common Object Request Broker Architecture (CORBA) specification, published by the Object Management Group (OMG) and x/Open.

This chapter describes DSOM from both perspectives.

DSOM features

Here is a quick summary of some of DSOM's more important features:

  • Uses the standard SOM Compiler, Interface Repository, language bindings, and class libraries. Thus, DSOM provides a growth path for non-distributed SOM applications.
  • Allows an application program to access a mix of local and remote objects. The fact that an object is remote is transparent to the program.
  • Provides run-time services for creating, destroying, identifying, locating, and dispatching methods on remote objects. These services can be overridden or augmented to suit the application.
  • Uses existing interprocess communication (IPC) facilities for Workstation communication, and common local area network (LAN) transport facilities for Workgroup communications. Support for TCP/IP, Netware IPX/SPX, and NetBios is provided. DSOM communications is extensible in that an application can provide its own transport.
  • Provides support for writing multi-threaded servers and event-driven programs.
  • Provides a default object server program, which can be easily used to create SOM objects and make those objects accessible to one or more client programs. If the default server program is used, SOM class libraries are loaded upon demand, so no server programming or compiling is necessary.
  • Complies with the CORBA 1.1 specification, which is important for application portability.

When to use DSOM

DSOM should be used for those applications that require sharing of objects among multiple programs. The object actually exists in only one process (this process is known as the object's server); the other processes (known as clients) access the object through remote method invocations, made transparent by DSOM.

DSOM should also be used for applications that require objects to be isolated from the main program. This is usually done in cases where reliability is a concern, either to protect the object from failures in other parts of the application, or to protect the application from an object.

Some distributed applications may have special performance, reliability,or cooperative processing requirements, to which the SOM Replication framework is better suited. The Replication framework is oriented toward "groupware" (multi-party cooperative processing) applications, and has facilities for fault tolerance and recovery. The Replication framework is distinct from DSOM in that it maintains a complete replica of an object in each participant's address space, while DSOM establishes remote connections to shared objects. The Replication Framework is available only in the full-capability SOM objects Developer Toolkit.

Chapter Outline

Briefly, this section covers the following subjects:

  • Tutorial example
  • Programming DSOM applications
  • Configuring DSOM applications
  • Running DSOM applications
  • DSOM and CORBA
  • Advanced topics
  • Error reporting and troubleshooting

Tutorial example

First, a complete example shows how an existing SOM class implementation (a "stack") can be used with DSOM to create a distributed "Stack" application. Using the "Stack" example as a backdrop, the basic DSOM interfaces are introduced.

Programming DSOM applications

All DSOM applications involve three kinds of programming:

  • Client programming: writing code that uses objects;
  • Server programming: writing code that implements and manages objects.
  • Implementing classes: writing code that implements objects.

Three sections ("Basic Client Programming", "Basic Server Programming", and Implementing Classes") describe how to create DSOM applications from these three points of view. In turn, the structure and services of the relevant DSOM run-time environment are explained.

Note: The three sections are presented in the order above to aid in their explanation. However, the actual programming tasks are likely to be performed in the opposite order.

Additional examples are provided in these sections to illustrate DSOM services.

Configuring DSOM applications

The section "Configuring DSOM Applications" explains what is necessary to set up a DSOM application, once the application has been built.

Running DSOM applications

The section "Running DSOM Applications" explains what is necessary to run a DSOM application, once it has been built and configured.

DSOM and CORBA

Those readers interested in using DSOM as a CORBA-compliant ORB should read the section entitled "DSOM as a CORBA compliant Object Broker." That section answers the question: How are CORBA concepts implemented in DSOM?

Advanced topics

The section on "Advanced Topics" covers the following:

  • Peer versus client/server processes" demonstrates how peer-to-peer object interactions are supported in DSOM.
  • Dynamic Invocation Interface" details DSOM support for the CORBA dynamic invocation interface to dynamically build and invoke methods on remote objects.
  • Creating user-supplied proxy classes" describes how to override proxy generation by the DSOM run time and, instead, install a proxy object supplied by the user.
  • Customizing the default base proxy class"discusses how the SOMDClientProxy class can be subclassed to define a customized base class that DSOM will use during dynamic proxy-class generation.
  • Sockets class" describes how DSOM uses Sockets subclasses.

Error reporting and troubleshooting

The section on "Error Reporting and Troubleshooting" discusses facilities to aid in problem diagnosis.

A Simple DSOM Example

A sample "Stack" application is presented in this section as a tutorial introduction to DSOM. It demonstrates that, for simple examples like a "Stack", after very little work, the class can be used to implement distributed objects that are accessed remotely. The example first presents the "Stack" application components and the steps that the implementer must perform before the application can be run, and then describes the run time activity that results from executing the application. This run-time scenario introduces several of the key architectural components of the DSOM run-time environment.

The source code for this example is provided with the DSOM samples in the SOMobjects Developer Toolkit.

The "Stack" interface

The example starts with the assumption that the class implementer has successfully built a SOM class library DLL, called "stack.dll", in the manner described in Section 5.6, "Creating a SOM Class Library," of Chapter 5, "Implementing Classes in SOM." The DLL implements the following IDL interface.

#include <somobj.idl>

interface Stack: SOMObject
{
    const long stackSize = 10;
    exception STACK_OVERFLOW{};
    exception STACK_UNDERFLOW{};
    boolean full();
    boolean empty();
    long top() raises(STACK_UNDERFLOW);
    long pop() raises(STACK_UNDERFLOW);
    void push(in long element) raises(STACK_OVERFLOW);

    #ifdef __SOMIDL__
    implementation
    {
      releaseorder: full, empty, top, pop, push;
      somDefaultInit: override;
      long stackTop;                  // top of stack index
      long stackValues[stackSize];    // stack elements
      dllname = "stack.dll";
    };
    #endif
};

This DLL could have been built without the knowledge that it would ever be accessed remotely (that is, built following the procedures in Chapter 5). Note, however, that some DLLs may require changes in the way their classes pass arguments and manage memory, in order to be used by remote clients (see the topic "Implementation Constraints" in section 6.5, "Implementing Classes").

The "Stack" class implementation

#define Stack_Class_Source
#include <stack.ih>

SOM_Scope boolean  SOMLINK full(Stack somSelf, Environment *ev)
{
    StackData *somThis = StackGetData(somSelf);
    StackMethodDebug("Stack","full");

    /* Return TRUE if stack is full. */
    return (_stackTop == stackSize);
}

SOM_Scope boolean  SOMLINK empty(Stack somSelf, Environment *ev)
{
    StackData *somThis = StackGetData(somSelf);
    StackMethodDebug("Stack","empty");

    /* Return TRUE if stack is empty.*/
    return (_stackTop == 0);
}

SOM_Scope long  SOMLINK top(Stack somSelf, Environment *ev)
{
    StackData *somThis = StackGetData(somSelf);
    StackMethodDebug("Stack","top");

    if (_stackTop > 0)
    {
       /* Return top element in stack without removing it from
        * the stack.
        */
       return (_stackValues[_stackTop-1]);
    }
    else
    {
       somSetException(ev, USER_EXCEPTION,
                       ex_STACK_UNDERFLOW, NULL);
       return (-1L);
    }
}

SOM_Scope long  SOMLINK pop(Stack somSelf, Environment *ev)
{
    StackData *somThis = StackGetData(somSelf);
    StackMethodDebug("Stack","pop");

    if (_stackTop > 0)
    {
       /* Return top element in stack and remove it from the
        * stack.
        */
       _stackTop--;
       return (_stackValues[_stackTop]);
    }
    else
    {
       somSetException(ev, USER_EXCEPTION,
                       ex_STACK_UNDERFLOW, NULL);
       return (-1L);
    }
}

SOM_Scope void  SOMLINK push(Stack somSelf,
                             Environment *ev, long el)
{
    StackData *somThis = StackGetData(somSelf);
    StackMethodDebug("Stack","push");

    if (_stackTop < stackSize)
    {
      /* Add element to top of the stack. */
      _stackValues[_stackTop] = el;
      _stackTop++;
    }
    else
    {
       somSetException(ev, USER_EXCEPTION,
                       ex_STACK_OVERFLOW, NULL);
    }
}

SOM_Scope void  SOMLINK somDefaultInit(Stack somSelf,
                                       somInitCtrl* ctrl)
{
    StackData *somThis;
    somInitCtrl globalCtrl;
    somBooleanVector myMask;
    StackMethodDebug("Stack","somDefaultInit");
    Stack_BeginInitializer_somDefaultInit;

    Stack_Init_SOMObject_somDefaultInit(somSelf, ctrl);

    /* stackTop is index into stackValues for next pushed
     * stack element.
     * stackValues[0..(stackSize-1)] holds stack elements.
     */
    _stackTop = 0;
}

Client program using a local stack

A simple client program written to use a local "Stack" object is displayed below. This C program is shown so that the differences between a local and remote client program can be highlighted.

#include <stack.h>

boolean OperationOK(Environment *ev);

int main(int argc, char *argv[])
{
  Environment ev;
  Stack stk;
  long num = 100;

  SOM_InitEnvironment(&ev);

  /* The StackNewClass invocation is optional and unnecessary
   * in the client program when the class object is created in
   * the SOMInitModule function that is invoked during DLL
   * initialization.
   */
  StackNewClass(Stack_MajorVersion, Stack_MinorVersion);
  stk = StackNew();

  /* Verify successful object creation */
  if ( stk != NULL )
  {
     while ( !_full(stk, &ev) )
     {
        _push(stk, &ev, num);
        somPrintf("Top: %d\n", _top(stk, &ev));
        num += 100;
     }

     /* Test stack overflow exception */
     _push(stk, &ev, num);
     OperationOK(&ev);

     while ( !_empty(stk, &ev) )
     {
        somPrintf("Pop: %d\n", _pop(stk, &ev));
     }

     /* Test stack underflow exception */
     somPrintf("Top Underflow: %d\n", _top(stk, &ev));
     OperationOK(&ev);
     somPrintf("Pop Underflow: %d\n", _pop(stk, &ev));
     OperationOK(&ev);

     _push(stk, &ev, -10000);
     somPrintf("Top: %d\n", _top(stk, &ev));
     somPrintf("Pop: %d\n", _top(stk, &ev));

     _somFree(stk);
  }

  SOM_UninitEnvironment(&ev);

  return(0);
}

boolean OperationOK(Environment *ev)
{
   char *exID;

   switch (ev->_major)
   {
     case SYSTEM_EXCEPTION:
       exID = somExceptionId(ev);
       somPrintf("System exception: %s\n", exID);
       somdExceptionFree(ev);
       return (FALSE);

     case USER_EXCEPTION:
       exID = somExceptionId(ev);
       somPrintf("User exception: %s\n", exID);
       somdExceptionFree(ev);
       return (FALSE);

     case NO_EXCEPTION:
       return (TRUE);

     default:
       somPrintf("Invalid exception type in Environment.\n");
       somdExceptionFree(ev);
       return (FALSE);
   }
}

Client program using a remote stack

The preceding program has been rewritten below showing how DSOM can be used to create and access a "Stack" object somewhere in the system. The exact location of the object does not matter to the application; it just wants a "Stack" object. Note that the stack operations of the two programs are identical. The main differences lie in stack creation and destruction, as highlighted below. (Also see "Memory management" later for more information on allocating and freeing memory.)

#include <somd.h>
#include <stack.h>

int main(int argc, char *argv])
{
  Environment ev;
  Stack stk;
  long num = 100;

  SOM_InitEnvironment(&ev);
  SOMD_Init(&ev);

  /* The StackNewClass invocation is optional and unnecessary
   * in the client program when the class object is created in
   * the SOMInitModule function that is invoked during DLL
   * initialization.
   */
  StackNewClass (Stack_MajorVersion, Stack_MinorVersion);   
  stk = _somdNewObject(SOMD_ObjectMgr, &ev, "Stack", "");

  /* Verify successful object creation */
  if ( OperationOK(&ev) )
  {
     while ( !_full(stk, &ev) )
     {
        _push(stk, &ev, num);
        somPrintf("Top: %d\n", _top(stk, &ev));
        num += 100;
     }

     /* Test stack overflow exception */
     _push(stk, &ev, num);
     OperationOK(&ev);

     while ( !_empty(stk, &ev) )
     {
        somPrintf("Pop: %d\n", _pop(stk, &ev));
     }

     /* Test stack underflow exception */
     somPrintf("Top Underflow: %d\n", _top(stk, &ev));
     OperationOK(&ev);
     somPrintf("Pop Underflow: %d\n", _pop(stk, &ev));
     OperationOK(&ev);

     _push(stk, &ev, -10000);
     somPrintf("Top: %d\n", _top(stk, &ev));
     somPrintf("Pop: %d\n", _top(stk, &ev));
        
     _somdDestroyObject(SOMD_ObjectMgr, &ev, stk);

     if ( OperationOK(&ev) )
     {
        somPrintf("Stack test successfully completed.\n");
     }
  }
  SOMD_Uninit(&ev);
  SOM_UninitEnvironment(&ev);

  return(0);
}

boolean OperationOK(Environment *ev)
{
   char *exID;

   switch (ev->_major)
   {
     case SYSTEM_EXCEPTION:
       exID = somExceptionId(ev);
       somPrintf("System exception: %s\n", exID);
       somdExceptionFree(ev);
       return (FALSE);

     case USER_EXCEPTION:
       exID = somExceptionId(ev);
       somPrintf("User exception: %s\n", exID);
       somdExceptionFree(ev);
       return (FALSE);

     case NO_EXCEPTION:
       return (TRUE);

     default:
       somPrintf("Invalid exception type in Environment.\n");
       somdExceptionFree(ev);
       return (FALSE);
   }
}

Let's step through the differences.

First, every DSOM program must include the file <somd.h> (when using C++, <somd.xh>). This file defines constants, global variables, and run-time interfaces used by DSOM. Usually, this file is sufficient to establish all necessary DSOM definitions.

Next, DSOM requires its own initialization call.

SOMD_Init(&ev);

The call to SOMD_Init initializes the DSOM run-time environment SOMD_Init must be called before any DSOM run-time calls are made. A side effect of calling SOMD_Init is that a run-time object, called the DSOM Object Manager, is created, and a pointer to it is stored in the global variable, SOMD_ObjectMgr, for programming convenience. The DSOM Object Manager provides basic run-time support for clients to find, create, destroy, and identify objects. The Object Manager is discussed in detail in the section entitled "Basic Client Programming."

Next, the local stack creation statement,

stk = StackNew();

was replaced by

stk = _somdNewObject(SOMD_ObjectMgr, &ev, "Stack", "");

The call to somdNewObject asks the DSOM Object Manager (SOMD_ObjectMgr) to create a "Stack" object, wherever it can find an implementation of "Stack". (There are other methods with which one can request specific servers.) If no object could be created, NULL is returned, and an exception is raised. Otherwise, the object returned is a "Stack" proxy.

Note: On AIX, the following call may be needed before the somdNewObject call, if the "Stack" class implementation has been linked directly with the program executable (vs. using a dynamic link library, or DLL). This call will properly initialize the class for use by DSOM (this initialization is done in SOMInitModulefor DLLs):

StackNewClass(Stack_MajorVersion, Stack_MinorVersion);

A proxy is an object that is a local representative for a remote target object. A proxy inherits the target object's interface, so it responds to the same methods. Operations invoked on the proxy are not executed locally, but are forwarded to the "real" target object for execution. The client program always has a proxy for each remote target object on which it operates.

From this point on, the client program treats the "Stack" proxy exactly as it would treat a local "Stack". The "Stack" proxy takes responsibility for forwarding requests to, and yielding results from, the remote "Stack". For example,

_push(stk,&ev,num);

causes a message representing the method call to be sent to the server process containing the remote object. The DSOM run-time in the server process decodes the message and invokes the method on the target object. The result (in this case, just an indication of completion) is then returned to the client process in a message. The DSOM run time in the client process decodes the result message and returns any result data to the caller.

At the end of the original client program, the local "Stack" was destroyed by the statement,

_somFree(stk);

whereas, in the client program above, the "Stack" proxy and the remote "Stack" are destroyed by the statement,

_somdDestroyObject(SOMD_ObjectMgr, &ev, stk);

If the client only wants to release its use of the remote object (freeing the proxy) without destroying the remote object, it can call the somdReleaseObject method instead of somdDestroyObject.

Finally, the client must shut down DSOM, so that any operating system resources acquired by DSOM for communications or process management can be returned:

SOMD_Uninit(&ev);

This call must be made at the end of every DSOM program.

Using specific servers

In DSOM, the process that manages a target object is called the object's server. Servers are implemented as programs that use SOM classes. Server implementations are registered with DSOM in an Implementation Repository. The Implementation Repository is a database queried by clients in order to find desired servers, and queried by DSOM in order to activate those servers upon demand.

The example above placed no constraints on the DSOM Object Manager as to where the remote "Stack" object should be created. The somdNewObject call creates a remote object of a specified class in an arbitrary server that implements that class. However, the DSOM Object Manager provides methods for finding specific servers.

For example, the client program above can be modified slightly to find a specific server named "StackServer", which has already been registered in DSOM's Implementation Repository. (Note that the programmer knew or discovered that the "StackServer" server implementation supports the "Stack" class.) The highlighted lines below show the changes that were made:

#include <somd.h>
#include <stack.h>

int main(int argc, char *argv[]) {
        Stack stk;
        Environment e;
        SOMDServer server;

        SOM_InitEnvironment(&e);
        SOMD_Init(&e);

        server =
          _somdFindServerByName(SOMD_ObjectMgr, &e, "StackServer");
        stk = _somdCreateObj(server, &e, "Stack", "");

        _push(stk,&e,100);
        _push(stk,&e,200);
        _pop(stk,&e);
        if (!_empty(stk,&e)) somPrintf("Top: %d\n", _top(stk,&e));

        _somdDeleteObj(server, &e, stk);
        _somdReleaseObject(SOMD_ObjectMgr, &e, stk);
        _somdReleaseObject(SOMD_ObjectMgr, &e, server);
        SOMD_Uninit(&e);
        SOM_UninitEnvironment(&e);

        return(0);
}

This version of the program replaces the somdNewObject operation with calls to somdFindServerByName and somdCreateObj. The somdFindServerByName method consults the Implementation Repository to find the DSOM server implementation whose name is "StackServer", and creates a server proxy, which provides a connection to that server. Every DSOM server process has a server object that defines methods to assist in the creation and management of objects in that server. Server objects must be instances of SOMDServer or one of its subclasses. The somdFindServerByName returns a proxy to the SOMDServer object in the named server.

Once the client has the server proxy, it can create and destroy objects in that server. The somdCreateObj call creates an object of the class "Stack" in the server named "StackServer".

To free the remote "Stack" object, the example shows a somdDeleteObj request on the stack object's server. Next, somdReleaseObject requests are made on the DSOM Object Manager, to free the stack proxy and the server proxy in the client. (Note that these three calls are equivalent to the somdDestroyObject call in the previous example.)

A note on finding existing objects

The two examples above show how clients can create a remote, transient object for their exclusive use. Clients may want to find and use objects that already exist. In that case, the calls to somdNewObject or somdCreateObj would be replaced with other "lookup" calls on some directory object that would take an object name or identifier and return a proxy to the remote object.

Such a directory object could be implemented by the application as a persistent SOM object, using DSOM to share it among processes.

The basic mechanisms that DSOM provides for naming and locating objects will be discussed in section "Basic Client Programming."

"Stack" server implementation

A server consists of three parts. First, a "main" program, when run, provides an address space for the objects it manages, and one or more process "threads" that can execute method calls. (Windows and AIX currently do not have multi-thread support, while OS/2 and AIX 4.1 do.) Second, a server object, derived from the SOMDServer class, provides methods used to manage objects in the server process. Third, one or more class libraries provide object implementations. Usually these libraries are constructed as dynamically linked libraries (DLLs), so they can be loaded and linked by a server program dynamically.

In this simple example, we can use the default DSOM server program, which is already compiled and linked. The default server behaves as a simple server, in that it simply receives and executes requests continuously. The default server creates its server object from the class, SOMDServer. The default server will load any class libraries it needs upon demand.

The "Stack" class library, "stack.dll", can be used without modification in the distributed application. This is possible because the "Stack" class is "well formed"; in other words, there are no methods that implicitly assume the client and the object are in the same address space.

Thus, by using the default server and the existing class library, a simple "Stack" server can be provided without any additional programming!

An application may require more functionality in the server program or the server object than the default implementations provide. A discussion on how to implement server programs and server objects is found later in this chapter, in section 6.4, "Basic Server Programming".

Compiling the application

DSOM programs and class libraries are compiled and linked like any other SOM program or library. The header file "somd.h" (or for C++, "somd.xh") should be included in any source program that uses DSOM services. DSOM run-time calls can be resolved by linking with the SOMobjects Toolkit library: "libsomtk.a" on AIX and "somtk.lib" on OS/2 or Windows. (The DSOM DLL(s) - "somd.dll", for AIX or OS/2, or "somd1.dll" and "somd1.dll" for Windows - will be loaded at run time.) For more information, see "Compiling and linking" in Chapter 3, "Using SOM classes in Client Programs," and the same topic in Chapter 5, "Implementing Classes in SOM."


Installing the implementation

Before the application can be run, certain environment variables must be set and the stack class and server implementations must be registered in the SOM Interface Repository and DSOM Implementation Repository.

Setting environment variables

Several environment variables are used by SOM and DSOM. These variables need to be set before registering the DSOM application in the Interface and Implementation Repositories.

For this example, the following environment variables could be set as shown. A full description of the environment variables and how to set them is given in section 6.6, "Configuring DSOM."

On AIX (in the syntax of the default shell, /bin/ksh):

export HOSTNAME=machine3
export SOMIR=$SOMBASE/etc/som.ir:/u/myuserid/my.ir
export SOMDDIR=/u/myuserid/somddir
export LIBPATH=$LIBPATH:$SOMBASE/lib:/u/myuserid/lib

On OS/2:

set USER=pat
set HOSTNAME=machine3
set SOMDDIR=c:\somddir

rem *** The following variables are set in CONFIG.SYS by
rem *** the install program on OS/2, assuming "c:\som" is the
rem *** value of %SOMBASE% supplied by the user.
set SOMIR=c:\som\etc\som.ir;som.ir
set LIBPATH=.;c:\som\lib;<previous LIBPATH>

On Windows:

set USER=pat
set HOSTNAME=machine3
set SOMDDIR=c:\somddir
rem *** The following variables are usually set in AUTOEXEC.BAT
rem *** by the install program on Windows, assuming "c:\som"
rem *** is the value of %SOMBASE% supplied by the user.
set SOMIR=c:\som\etc\som.ir:som.ir
set PATH=.;c:\som\lib;<previous PATH>

USER identifies the user of a DSOM client application. DSOM sends the USER ID with every remote method call, in case the remote object wishes to perform any access control checking. This is discussed later in the section "Basic Server Programming." (Note that USER is usually set automatically by AIX when a user logs in.)

HOSTNAME identifies the name of each machine running DSOM.

SOMIR gives a list of files that together constitute the Interface Repository. The IR is used by DSOM to guide the construction and interpretation of request messages. For DSOM, it is preferable to use full pathnames in the list of IR files, since the IR will be shared by several programs that may not all reside in the same directory.

SOMDDIR gives the name of a directory used to store DSOM configuration files, including the Implementation Repository.

LIBPATH (on AIX and OS/2) or PATH (on Windows) gives a list of directories where DLLs can be found.

Registering the class in the Interface Repository

Before an object can be accessed remotely by DSOM, it is necessary to register the class's interface and implementation in the Interface Repository (IR). DSOM uses the interface information when transforming local method calls on proxies into request messages transmitted to remote objects.

DSOM servers also consult the IR to find the name of the DLL for a dynamically loaded class. The DLL name for the "Stack" class must be specified using the dllname="stack.dll" modifier in the implementation statement of the "Stack" IDL. The Interface Repository is described in detail in Chapter 7, "The Interface Repository Framework."

The IDL specification of "Stack" is compiled into the Interface Repository using the following command:

       sc -u -sir stack.idl               (on AIX or OS/2)
       somc -u -sir stack.idl             (on Windows)


When a class has not been compiled into the Interface Repository, DSOM will generate a run-time error when an attempt is made to invoke a method from that class. The error indicates that the method's descriptor was not found in the IR.

Registering the server in the Implementation Repository

It is necessary to register a description of a server's implementation in the Implementation Repository. DSOM uses this information to assist clients in finding servers, and in activating server processes upon demand.

For this example, where the default server is used, we need only to identify the server's name, and the class that the server implements. This is accomplished using the regimpl utility discussed in section 6.6, "Configuring DSOM Applications". The following commands define a default server, named "StackServer", which supports the Stack class:

       regimpl -A -i StackServer
       regimpl -a -i StackServer -c Stack

Running the application

This section discusses:

  • Starting the DSOM daemon
  • Running the client
Starting the DSOM daemon

Before running a DSOM application, the DSOM daemon, somdd, must be started.

  • On AIX or OS/2, the daemon can be started manually from the command line, or it could be started automatically from a start-up script run at boot time. It may be run in the background with the commands somdd& on AIX and start somdd on OS/2. (The somdd program requires no parameters. An optional -q parameter can be used to set "quiet" mode, to suppress messages.)
  • On Windows, the daemon can be started with the DSOM Daemon icon in the SOM icon group or started in Windows from the Run option of the file menu. The DSOM Daemon icon will change colors to indicate the daemon is ready, after which client and server programs can be started.

The somdd daemon is responsible for establishing a "binding" (that is, a connection) between a client process and a server. It will activate the desired server automatically, if necessary. The server can also be started manually prior to starting the client program, using the command dsom start stackServer.

Running the client

Once the DSOM daemon is running, the application may be started. This is accomplished by running the client program. If the StackServer is not running, it will be started automatically by the DSOM daemon when the client attempts to invoke a method on one of its objects. After the client program ends, the server will continue to run, accepting connections from new clients. To terminate the server, use the command dsom stop stackServer.

"Stack" example run-time scenario

The following scenario steps through the actions taken by the DSOM run time in response to each line of code in the second "Stack" client program presented above. The illustration following the scenario shows the processes, and the objects within them, that participate in these actions.

  • Initialize an environment for error passing:
SOM_InitEnvironment(&e);
  • Initialize DSOM:
SOMD_Init(&e);

This causes the creation of the DSOM Object Manager (with SOMDObjectMgr interface). The global variable SOMD_ObjectMgr points to this object.

  • Initialize "Stack" class object:
StackNewClass(Stack_MajorVersion, Stack_MinorVersion);
  • Find the "StackServer" implementation and assign its proxy to the variable server:
server = _somdFindServerByName(SOMD_ObjectMgr, &e, "StackServer");

This causes the creation of the server proxy object in the client process. Proxy objects are shown as shaded circles. Note that the "real" server object in the server process is not created at this time. In fact, the server process has not yet been started.

  • Ask the server object to create a "Stack" and assign "Stack" proxy to variable stack.
stk = _somdCreateObj(server, &e, "Stack", "");

This causes somdd, the DSOM daemon (which is already running) to activate the stack server process (by starting the "generic" server program). The stack server process, upon activation, creates the "real" SOMDServer object in the server process. The SOMDServer object works with the DSOM run time to create a local "Stack" object and return a "Stack" proxy to the client. (The details of this procedure are deferred until section 6.4, "Basic Server Programming".)

  • Ask the "Stack" proxy to push 100 onto the remote stack:
_push(stk,&e,100);

This causes a message representing the method call to be marshalled and sent to the server process. In the server process, DSOM demarshals the message and, with the help of the SOMDServer, locates the target "Stack" object upon which it invokes the method ("push"). The result (which is void in this case) is then passed back to the client process in a message.

  • Invoke more "Stack" operations on the remote stack, via the proxy:
_push(stk,&e,200);
_pop(stk,&e);
if (!_empty(stk,&e)) t = _top(stk,&e);
  • Explicitly destroy both the remote stack, the stack proxy, and the server proxy:
_somdDeleteObj(server, &e, stk);
_somdReleaseObject(SOMD_ObjectMgr, &e, stk);
_somdReleaseObject(SOMD_ObjectMgr, &e, server);
  • Free the error-passing environment:
SOM_UninitEnvironment(&e);

This scenario has introduced the key processes in a DSOM application: client, server, and somdd. Also introduced are the key objects that comprise the DSOM run-time environment: the SOMD_ObjectMgr in the client process and the SOMD_ServerObject in the server process.

Summary

This example has introduced the key concepts of building, installing, and running a DSOM application. It has also introduced some of the key components that comprise the DSOM application run-time environment.

The following sections, "Basic Client Programming," "Basic Server Programming," and "Implementing Classes," provide more detail on how to use, manage, and implement remote objects, respectively.

Basic Client Programming

For the most part, client programming in DSOM is exactly the same as client programming in SOM, since DSOM transparently hides the fact that an object is remote when the client accesses the object.

However, a client application writer also needs to know how to create, locate, use, save, and destroy remote objects. (This is not done using the usual SOM bindings.) The DSOM run-time environment provides these services to client programs primarily through the DSOM Object Manager. These run-time services will be detailed in this section. Examples of how an application developer uses these services are provided throughout the section.

DSOM Object Manager

DSOM defines a DSOM Object Manager, which provides services needed by clients to create, find and use objects in the DSOM run-time environment.

The DSOM Object Manager is derived from an abstract, generic "object manager" class, called ObjectMgr. This abstract ObjectMgr class defines a basic set of methods that support object creation, location (with implicit activation), and destruction.

As an abstract class, ObjectMgr defines only an interface; there is no implementation associated with ObjectMgr. Consequently, an application should not create instances of the ObjectMgr class.

An abstract Object Manager class was defined under the expectation that applications will often need simultaneous access to objects implemented and controlled by a variety of object systems. Such object systems may include other ORBs (in addition to DSOM), persistent object managers, object-oriented databases, and so forth. It is likely that each object system will provide the same sort of basic services for object creation, location, and activation, but each using a different interface.

Thus, the ObjectMgr abstract class defines a simple and "universal" interface that can be mapped to any object system. The application would only have to understand a single, common ObjectMgr interface. Under this scheme, specific object managers are defined by subclassing the ObjectMgr class and overriding the ObjectMgr methods to map them into the object system-specific programming interfaces.

DSOM's Object Manager, SOMDObjectMgr, is defined as a specific class of ObjectMgr. It defines methods for:

  • Finding servers that implement particular kinds of objects
  • Creating objects in servers
  • Obtaining object identifiers (string IDs)
  • Finding objects, given their identifiers
  • Releasing and destroying objects

These functions will be discussed in the remainder of this section.

Note
The OMG has standardized an "object lifecycle" service, which includes support for creating and destroying distributed objects. The DSOM Object Manager may be augmented in the future with an OMG-compliant lifecycle service.


Initializing a client program

A client application must declare and initialize the DSOM run time before attempting to create or access a remote object. The SOMD_Init procedure initializes all of the DSOM run time, including the SOMDObjectMgr object. The global variable, SOMD_ObjectMgr is initialized to point to the local DSOM Object Manager.

A client application must also initialize all application classes used by the program. For each class, the corresponding <className>NewClass call should be made.

Note: In non-distributed SOM programs, the <className>New macro (and the new operator provided for each class by the SOM C++ bindings) implicitly calls the procedure <className>NewClass when creating a new object. This is not currently possible in DSOM because, when creating remote objects, DSOM uses a generic method that is not class-specific.


This was shown in the "Stack" example in section 6.2. In a similar example of an application that uses "Car" and "Driver" objects, the initialization code might look like this:

#include <somd.h>    /* needed by all clients */
#include <Car.h>     /* needed to access remote Car */
#include <Driver.h>  /* needed to access remote Driver */

main()
{
    Environment ev; /* ev used for error passing */
    SOM_InitEnvironment(&ev);

    /* Do DSOM initialization */
    SOMD_Init(&ev);

    /* Initialize application classes */
    CarNewClass(Car_MajorVersion, Car_MinorVersion);
    DriverNewClass(Driver_MajorVersion, Driver_MinorVersion);
    ...
}

As shown, client programs should include the "somd.h" file (or, for C++ programs, the "somd.xh" file) in order to define the DSOM run#time interfaces.

Note also that, since Environments are used for passing error results between a method and its caller, an Environment variable (ev) must be declared and initialized for this purpose.

The calls to "CarNewClass" and "DriverNewClass" are required if the client will be creating or accessing Cars and Drivers. The procedures "CarNewClass" and "DriverNewClass" create class objects for the classes "Car" and "Driver". When a DSOM Object Manager method like somdNewObject is invoked to create a "Car", it expects the "Car" class object to exist. If the class does not yet exist, the "ClassNotFound" exception will be returned.

Exiting a client program

At the end of a client program, the SOMD_Uninit procedure must be called to free DSOM run-time objects, and to release system resources such as semaphores, shared memory segments, and so on. SOMD_Uninit should be called even if the client program terminates unsuccessfully; otherwise, system resources will not be released.

For example, the exit code in the client program might look like this:

    ...
    SOMD_Uninit(&e);
    SOM_UninitEnvironment(&e);
}

Note also the SOM_UninitEnvironment call, which frees any memory associated with the specified Environment structure.

Note
When a Windows DSOM client receives a WM-QUIT message while processing a remote method invocation, DSOM will clean up and terminate the client without returning to the client's WinProc or WinMain.


Creating remote objects

Distributed objects can be created in several different ways in DSOM.

  • The client can create an object on any server that implements that class of object.
  • The client can find a specific server upon which to create an object.
  • A server can create an object and register a reference to the object in some well-known directory. (An object reference contains information that reliably identifies a particular object.)

The first two cases are discussed immediately below. The last case is discussed near the end of this section.

Creating an object in an arbitrary server

Following is an example of how to create a new remote object in the case where the client does not care in which server the object is created. In this situation, the client defers these decisions to the DSOM Object Manager (SOMD_ObjectMgr) by using the somdNewObject method call, which has this IDL definition:

  // (from file om.idl)


  SOMObject somdNewObject(in Identifier objclass, in string hints);

  // Returns a new object of the named class.  This is a "basic"
  // creation method, where the decisions about where and how to
  // create the object are mostly left up to the Object Manager.
  // However, the Object Manager may optionally define creation
  // "hints" which the client may specify in this call.


Here is the example of how a remote "Car" would be created using somdNewObject:

#include <somd.h>
#include <Car.h>

main()
{
    Environment ev;
    Car car;

    SOM_InitEnvironment(&ev);
    SOMD_Init(&ev);

    /* create the class object */
    CarNewClass(Car_MajorVersion, Car_MinorVersion);

    /* create a Car object on some server, let the
       Object Manager choose which one */
    car = _somdNewObject(SOMD_ObjectMgr, &ev, "Car", "");
    ...
}

The main argument to the somdNewObject method call is a string specifying the name of the class of the desired object. The last argument is a string that may contain "hints" for the Object Manager when choosing a server. In this example, the client is providing no hints. (Currently, the DSOM Object Manager simply passes the hints to the server object in a somdCreateObj call.)

Proxy objects

As far as the client program is concerned, when a remote object is created, a pointer to the object is returned. However, what is actually returned is a pointer to a proxy object, which is a local representative for the remote target object.

Proxies are responsible for ensuring that operations invoked on it get forwarded to the "real" target object that it represents. The DSOM run time creates proxy objects automatically, wherever an object is returned as a result of some remote operation. The client program will always have a proxy for each remote target object on which it operates. Proxies are described further in the sections entitled "DSOM as a CORBA-compliant Object Request Broker" and "Advanced Topics".

In the example above, a pointer to a "Car" proxy is returned and put in the variable "car". Any subsequent methods invoked on "car" will be forwarded and executed on the corresponding remote "Car" object.

Proxy objects inherit behavior from the SOMDClientProxy class.

Servers and server objects

In DSOM, the process that manages a target object is called the object's server. Servers are implemented as programs that use SOM classes. The example above placed no constraints on the DSOM Object Manager as to which server should create the remote "Car" object. However, if the client desires more control over distribution of objects, the DSOM Object Manager provides methods for finding specific servers.

Server implementations are registered with DSOM in an Implementation Repository. Server implementations are described by a unique ID, a unique (user-friendly) name, the program name that implements the server, the classes that are implemented by the server, the machine on which the server is located, whether the server is multi-threaded, and so forth. (See section 6.6 for more information on registering server implementations.) A client can ask the DSOM Object Manager to find a particular server:

  • By name
  • By ID
  • By a class it supports

When a client asks for a "server", it is given (a proxy to) a server object that provides interfaces for managing the objects in the server. There is one server object per server process. All server objects are instances of the SOMDServer class, or its subclasses. The default method provided by SOMDServer for creating objects is:

  // (from file somdserv.idl)

  SOMObject somdCreateObj(in Identifier objclass, in string hints);

  // Creates an object of the specified class.  This method
  // may optionally define creation "hints" which the client
  // may specify in this call.  (Hints are ignored by default.)

Section 6.4 explains how to create application-specific server objects, derived from SOMDServer, which override SOMDServer methods and introduce their own methods for object management.

Creating an object in a specific server

The following example demonstrates how a client application creates a new object in a remote server chosen by the client. The DSOM Object Manager method somdFindServerByName is used to find and create a proxy to the server object for the server implementation named "myCarServer". The method somdCreateObj is then invoked on the server object to create the remote "Car". A proxy to the remote "Car" is returned. (The "Stack" client presented in the previous section used the same methods to create a remote "Stack".)

 /* find a specific Car server */
    server =
      _somdFindServerByName(SOMD_ObjectMgr, &ev, "myCarSe           rver");

 /* create a remote Car object on that server */
    car = _somdCreateObj(server, &ev, "Car", "");
    ...
}
Note
If the specified server does not provide any implementation of the desired class, a NULL pointer will be returned and a "ClassNotFound" exception will be raised.


Three other methods can be invoked on the DSOM Object Manager to find server implementations: somdFindServer, somdFindServersByClass, and somdFindAnyServerByClass. The IDL declarations of these methods follow:

SOMDServer somdFindServer(in ImplId serverid);

sequence<SOMDServer> somdFindServersByClass(in Identifier objclass);

SOMDServer somdFindAnyServerByClass(in Identifier objclass);

The somdFindServer method is similar to the somdFindServerByName method, except that the server's implementation ID (of type ImplId) is used to identify the server instead of the server's user-friendly name (or "alias"). The implementation ID is a unique string generated by the Implementation Repository during server registration. (See section 6.6 for more details.)

The somdFindServersByClass method, given a class name, returns a sequence of all servers that support the given class. The client program may then choose which server to use, based on the server's name, program, or other implementation attributes (e.g., the server is multi-threaded). (See the topic below, "Inquiring about a remote object's implementation.")

Finally, the somdFindAnyServerByClass method simply selects any one of the server implementations registered in the Implementation Repository that supports the given class, and returns a server proxy for that server.

Once the server proxy is obtained, methods like somdCreateObj, shown in the example above, can be invoked upon it to create new objects.

Inquiring about a remote object's implementation

Destroying remote objects

Destroying objects via a proxy

Destroying objects via the DSOM Object Manager

Destroying objects via a server object

Creating remote objects using user-defined metaclasses

Saving and restoring references to objects

Finding existing objects

Finding server objects

Invoking methods on remote objects

Determining memory allocation and ownership

Passing object references in method calls

Memory management

Memory management for method parameters

The CORBA policy for parameter memory management

The 'somdReleaseResources' method and object-owned parameters

Writing clients that are also servers

Compiling and linking clients

Basic Server Programming

       Server run-time objects
           Server implementation definition
           SOM Object Adapter (SOMOA)
           Server object 
       Server activation
       Initializing a server program
           Initializing the DSOM run-time environment
           Initializing the server's ImplementationDef
           Initializing the SOM Object Adapter
           When initialization fails 
       Processing requests
       Exiting a server program
       Managing objects in the server
           Object references, ReferenceData, and the ReferenceData table
           Simple SOM object references
           SOMDServer (default server-object class)
           Creation and destruction of SOM objects
           Mapping objects to object references
           Hints on the use of create vs. create_constant
           Mapping object references to objects
           Dispatching a method 
       Example: Writing a persistent object server
       Identifying the source of a request
       Compiling and linking servers 

Implementing Classes

       Using SOM class libraries
           Role of DSOM generic server program
           Role of SOM Object Adapter
           Role of SOMDServer
           Implementation constraints 
       Using other object implementations
           Wrapping a printer API 
       Parameter memory management
       Building and registering class libraries 

Configuring DSOM Applications

       Preparing the environment
       Registering class interfaces
       Registering servers and classes
       The 'regimpl', 'pregimpl', 'wregimpl' registration utilities
           Registration steps Using 'regimpl'
           Command line interface to 'regimpl'
           Registration steps using 'pregimpl' or 'wregimpl' 
       Programmatic interface to the Implementation Repository
       The 'dsom' server manager utility
           Interpretation of 'dsom' messages 
       Verifying the DSOM environment with 'somdchk'
       Freeing interprocess communication resources on AIX
           Using 'somdclean'
           Using 'cleanipc' 

Running DSOM Applications

       Running the DSOM daemon (somdd)
       Running DSOM servers 

DSOM as a CORBA-compliant Object Request Broker

       Mapping OMG CORBA terminology onto DSOM
           Object Request Broker run-time interfaces
           Object references and proxy objects
           Creation of remote objects
           Interface definition language
           C language mapping
           Dynamic Invocation Interface (DII)
           Implementations and servers
           Object Adapters
           Extensions and limitations 

Advanced Topics

       Peer vs. client/server processes
           Multi-threaded DSOM programs
           Event-driven DSOM programs using EMan
           Sample server using EMan 
       Dynamic Invocation Interface
           The NamedValue structure
           The NVList class
           Creating argument lists
           Building a Request
           Initiating a Request
           Example code 
       Creating user-supplied proxies
       Customizing the default base proxy class
       Sockets class 

Error Reporting and Troubleshooting

       Error codes
       Troubleshooting hints
           Checking the DSOM setup
           Analyzing problem conditions

Limitations