Object-Oriented Programming Using SOM and DSOM/Introduction

What is SOM?
SOM stands for System Object Model. It is a new model for developing and pack­aging object-oriented software. SOM offers different benefits to different people:
 * To those who build and distribute class libraries: SOM can save the users of the class libraries from recompiling their source code every time there is a new release of the class library.
 * To those who would like to adopt object technology but want to use a more familiar language, such as C or COBOL, for their development: SOM offers language bindings that let you implement your classes in a variety of lan­guages.
 * To those who want to build distributed applications: the Distributed SOM Framework provides transparent access to objects that are distributed across address spaces on different machines.
 * To those who are interested in saving objects: the Persistence SOM Framework allows you to store objects in a persistent store, such as a file system or a rela­tional database, and then restore the objects at a later time.
 * To those who are interested in providing workgroup solutions:the Replication SOM Framework allows you to replicate your objects across different address spaces and handles the propagation of updates to all replicated copies of an object.
 * To the compiler vendors who would like to supply SOM bindings for their com­pilers: the Emitter Framework allows you to parse an interface definition so that you can use the returned information to produce your own language emit­ters, without having to write your own IDL compiler.

Why SOM?
SOM was developed to promote better software reuse. The original SOM archi­tects discovered  that although object-oriented programming promises great reuse potential, in reality, this was quite difficult. One of the problems is that dif­ferent languages have different programming models. Classes developed in one language cannot be easily used in another language. For example, a class library developed in C++ cannot be easily used by a Smalltalk program, and a OOCO­BOL program cannot easily use a Smalltalk class. This situation is even worse in C++, where classes built with different C++ compilers are often incompatible with one another.

SOM solves this problem by providing a language-neutral object model. Using SOM, classes can be developed in one language, and used in another language. SOM supports the common object-oriented concepts, such as classes, abstraction, and inheritance. This makes it possible for programmers who use procedural languages to also design and implement in an object-oriented fashion.

Since SOM is language neutral, you will find that some language-specific fea­tures are not supported in SOM. For example, SOM does not support C++ tem­plates; however, you do not have to use SOM in your entire application. You can implement some objects as C++ objects and some objects as SOM objects. You can use C++, Smalltalk, or other languages to implement your internal objects and use SOM only when you want the functions to be accessed by different languages.

SOM also allows you to distribute class libraries as dynamic link libraries, without requiring recompilation of application source code. For libraries that are developed in procedure-based language, maintaining upward binary compatibil­ity is normally not a problem. However, for libraries that are developed in object­ oriented languages such as C++, structural changes in a class interface, such as when new methods are added, will require recompilation of client programs. This can present a serious problem, because recompilation might not be possible in cases when the source code is not available.

SOM Architecture
Figure 1.1 shows the architecture of SOM. The Language Neutral Object Inter­face Definition defines the interface to an object. An interface contains only the information that the client of the object must know in order to use the object. The internal details, or the implementation of the object, are not included in the interface. The interface is described in a formal language called the Interface Definition Language (IDL), which is independent of other programming languages.

The SOM compiler compiles the interface definition to produce language-spe­cific bindings. A language binding maps an IDL concept to a specific language construct. For example, an IDL inheritance specification might be mapped directly onto an inheritance construct in a language that supports inheritance, or to a procedure declaration in a language that has no notion of inheritance. The boundary between the language specific bindings to the SOM objects indi­cates that a client can use any of the supported languages to invoke a SOM object, regardless of the language in which the SOM object is implemented. The protocol between the language bindings and the SOM objects is based on simple procedure calls. For each language binding, the SOM compiler generates the appropriate application programming interfaces (APIs) to the SOM objects.

The SOM Run-Time Object Repository provides functions for creating objects and invoking methods on the objects. It also maintains a registry of all classes in the current process, and assists in the dynamic loading and unloading of classes. We will explore this in more detail in Chapter 3.

SOM Components
SOM has now gone well beyond the initial objective of providing a common object model for different languages and maintaining upward binary compatibility of class libraries. In release 2.0, SOM introduced a number of additional compo­nents that help programmers develop object-oriented applications. Figure 1.2 shows all the components in SOM. A description of each component follows.
 * SOM Run-Time Kernel:The SOM run-time kernel provides a set of functions for creating objects and invoking methods on them. Other SOM components are built on the run-time kernel.
 * Distributed SOM:Distributed SOM (DSOM) is a framework that supports access to objects in a dis­tributed application. An application can use DSOM to access objects in other pro­cesses, even on different machines.
 * Persistence SOM:Persistence SOM (PSOM) is a framework that supports storing and restoring of objects. An application can use PSOM to preserve the state of an object beyond the existence of the process that creates the object.
 * Replication SOM:Replication SOM (RSOM) is a framework that allows a replica (copy) of an object to exist in multiple address spaces while maintaining a single-copy image. Updates to any copy are propagated immediately to all other copies. An applica­tion can use RSOM to instantaneously share common data objects.
 * Interface Repository:The Interface Repository is a database that contains all the information in an interface definition. An application can use the Interface Repository, at run-time, to find all the information that is stored in the IDL description of an object.
 * Emitter Framework:The Emitter Framework is a collection of classes that assist users who would like to provide language specific bindings or other more general emitters such as documentation for IDL. It off-loads the burden of having to write IDL parsers for these programmers. It also provides a template facility for specifying the output format.
 * Collection Classes:The Collection Classes are a large group of classes provided for the program­mer's convenience. They implement most of the frequently used data structures such as lists, sets, queues, stacks, hash table, and dictionaries. These classes originated from a company named Taligent and were first implemented in C++. Taligent is jointly owned by IBM, Apple and Hewlett-Packard. Its mission is to create a new desktop environment that is object-based from the ground up. These classes have been made into SOM classes for use with the SOM Toolkit.
 * Event Management:The Event Management Framework is a central facility for registering all events of an application. It provides a way to group application events and to process all events in a single event-processing loop. This is useful for interactive applica­tions that need to process background events, such as messages arriving from a remote process. This framework is particularly useful in a single-threaded envi­ronment, as it allows an application to recognize and process all events in a sin­gle main loop.
 * Utility Metaclass:The Utility Metaclass provides a facility that guarantees the creation of only one instance of a class.
 * SOM Compiler:The SOM compiler is a tool that helps programmers build classes where the interface is separated from the implementation. The SOM compiler reads an interface definition, then generates the bindings and implementation skeleton for a class.

SOM, OMG and CORBA
The Object Management Group (OMG) is a consortium that was formed in 1989 with the purpose of creating industry standards for commercially available object-oriented systems by focusing on Distributed Applications, Distributed Ser­vices, and Common Facilities. Its mission is to define a set of standard interfaces for inter-operable software components. The first specification defined is an Object Request Broker (ORB). It provides the mechanisms by which objects transparently make, and receive, requests and responses. In so doing, the ORB provides inter-operability between applications on different machines in hetero­geneous distributed environments and seamlessly interconnects multiple object systems.

In September 1991, OMG selected a standard interface for the ORB. This interlace is called the Common Object Request Broker Architecture (CORBA). It is a joint proposal of Digital Equipment Corporation, Hewlett-Packard Company, HyperDesk Corporation, NCR Corporation, Object Design Inc., and SunSoft Cor­poration. The most important feature of the CORBA specification is its Interlace Definition Language (IDL). The IDL language is used to describe the interlaces that client objects call and object implementation provides

So why is this important? It is important because Distributed SOM is an ORB and complies with the CORBA specification. Therefore, a lot of the interfaces of SOM and DSOM are determined by the CORBA specification. DSOM is built on top of SOM in order to take advantage of the language neutral and the upward binary compatibility capabilities. However, it is important to realize that the implementation of DSOM does not need to be surfaced to the application.

Some of the mappings from the SOM and DSOM implementation to the CORBA specification are given below:
 * Interface Definition Language:CORBA defines IDL as the language for defining object interfaces. The SOM compiler compiles standard CORBA IDL.
 * C Language Mapping:CORBA defines the mapping of method interface definitions to C language procedure prototypes. The SOM compiler generates the same mappings for C bindings.
 * Dynamic Invocation Interface:CORBA defines a Dynamic Invocation Interface (DII) that allows the dynamic construction of object invocations. A request to an object using the DII has the same semantics as a request through a stub routine to the object. SOM sup­ports invocation on an object using the DII.
 * Interface Repository:CORBA defines an Interface Repository (IR) that provides persistent storage for interface definitions.The information stored in the Interface Repository may be used by the ORB to perform requests. CORBA also defines operations for retrieving information from the Interface Repository.
 * SOM includes an Interface Repository emitter that can be used to create or update an Interface Repository. SOM also provides a Repository class for accessing the Interface Repository.


 * ORB Programming Interfaces:CORBA defines an interface that goes directly to the ORB. The ORB interface defines operations for converting object references to strings, and converting strings to object references. The ORB interface also defines operations for cre­ating lists and determines the default context used in the Dynamic Invocation Interface. DSOM provides an ORB class that implements these specifications.

There are many aspects of the CORBA specification. We have highlighted some of them here. Readers interested in more detail should refer to the CORBA specification and the SOMobjects Developer Toolkit User's Guide.

A First Look at IDL
IDL, as defined by CORBA, is a declarative language that is used to describe the interface of an object. An interface is a description of a set of possible operations that a client may request of an object. An IDL specification can include the fol­lowing elements:

Constant declarations

 * Type declarations:This can include basic types (e.g., short, long, float, and double), constructed types (e.g., structures and discriminated unions), and template types (e.g., sequences and strings).
 * Attribute declarations:An attribute is modeled as a pair of accessor functions, one to get the value of the attribute, the other to set the value of the attribute.
 * Operation (method) declarations:An operation is used to define the services provided by an object. It has a sig­nature that consists of:
 * Parameters that are required for the operation
 * Results of the operation
 * Exceptions that may be raised by the operation
 * Contextual information that may affect the request
 * Execution semantics of the request
 * Exception declarations:This allows the declaration of data structures that can be used to return exception conditions.
 * Module declarations:A module is used to scope IDL identifiers.

IDL also allows the specification of interface inheritance. One interface can be derived from another interface. The derived interface can define new elements, as well as redefine any of the attributes, operations, and types of the base inter­face.

The following is an example of an IDL. The name of the interface is Book, and it is derived from the Document interface. A client of a Book object can invoke the get or set operation on the attribute title. A client of a Book object can also invoke the print method. interface Book: Document {    attribute string title; long print(in short pageNum); };

SOM IDL, CORBA IDL, and OIDL
SOM IDL is an extension of the CORBA IDL. There are two main extensions:

Implementation statement
A SOM IDL may contain an implementation statement that specifies implementation information about a class. Implementation information may include things like the version number of the class, the name of the dynamic library in which the class resides, etc. Since the implementation statement is specific to SOM IDL, it should be preceded by an #ifdef _SOMIDL_ directive and followed by an #endif directive. The following shows an example of a SOM IDL: interface Book : Document {  attribute string title; long print(in short pageNum); #ifdef _SOMIDL_ Implementation {     dllname = "document.dll"; };  #endif }; Any statements that are defined in the implementation section are not CORBA and therefore will not be understood by other IDL compilers. The details of the allowable constructs in the implementation section will be described in different sections throughout the book.

Support of pointer types
In addition to supporting the base CORBA types, SOM IDL also permits the use of pointer types. Pointer types allow the construction of more complex data types and are also supported by the predecessor, Object Interface Defini­tion Language (OIDL). However, the use of pointer types for new interfaces should be avoided, where possible, to ensure the maximum portability of the IDL definitions.

OIDL is the SOM Object Interface Definition Language in release 1.0. It was defined prior to the CORBA specification. When IDL was defined by CORBA, SOM quickly moved to support the standardized language. The SOM Toolkit supplies a program, ctoi, to assist users in converting interface definitions that are written in OIDL to IDL.

There are a number of reasons why OIDL users should convert to IDL. IDL offers multiple inheritance, exception handling, and type checking that are not available in OIDL. More importantly, however, the frameworks that were added in release 2.0, such as DSOM, require the use of IDL. Users who do not want to convert their OIDL descriptions to IDL can continue to use the SOM compiler to generate binding files from OIDL descriptions.

Throughout this book, we will be using SOM IDL. When we use the term IDL, we mean SOM IDL unless otherwise specified.

Language Bindings
While IDL defines the interface to an object, client programs that use the object are not written in IDL. Instead, they are written in languages where language bindings have been defined. Figure 1.1 showed the different language bindings. The C and C++ language bindings are currently available from IBM and are shipped with the SOM Toolkit.

C Language Binding Syntax
Let's take a look at the syntax that a C client would use to invoke the print method on a Book object whose IDL is shown in the previous section. We will assume that a pointer to the Book object is stored in the variable mybook and not worry about how to obtain a pointer to this object for now. The following shows the C fragment that invokes the print method. _print(mybook, ev, 10); At first glance, this statement might look somewhat bizarre. Why is the name of the method preceded with an underscore, and why are there three arguments, as opposed to one argument, defined in the IDL specification? The following para­ graphs will explain. The underscore before the method name is actually a short form representation. It has a long form which follows: Book_print(mybook, ev, 10); The long form is defined by the C Language Mapping in CORBA. The name of a method is qualified with the interface name to provide the correct scoping. The SOM C bindings simply provide a convenient short-form macro that is also com­patible with release 1.0. The long-form macro is always generated in the C bind­ing files and can be used instead of the short form. If you want better code portability to other vendors' platforms that support CORBA, stick with the long form. In addition, if there is any ambiguity that may arise if a client uses two interfaces introducing the same method name, the long form should be used.

In order to invoke a method on an object, the object must be specified in the statement. Since C is a procedural language, it does not have the notion of an object. Therefore, a natural way of including an object will be as an argument in the call. This is what the CORBA specification defines and what the SOM C binding implements.

The second argument, ev, is a pointer to the Environment data structure that is defined by CORBA. It is used to pass exception information between the caller, and the called, method. The Environment structure is discussed in more detail in Section 3.14 on page 60. The C Language Mapping in CORBA designates the second parameter of an operation to be a pointer to the Environment structure and this is what the SOM C binding implements.

The third argument, 10, is the page number parameter for the print method. The following summarizes the argument syntax, when using the SOM C lan­guage bindings.
 * 1) An invocation to a method defined in IDL requires at least two arguments. The first one is a pointer to the object that responds to the method. The second one is a pointer to the Environment structure.
 * 2) If the IDL specification of the method includes a context specification, then a Context parameter must be specified immediately after the Environment pointer argument. Otherwise, this parameter is not needed as shown in this example. See Section 3.15 on page 63 for a detailed discussion on context. Note that none of the SOM supplied methods require context arguments.
 * 3) The remaining arguments correspond to the parameters specified in the IDL.

For compatibility with the SOM 1.0 C bindings, there is one final exception to the argument rules. This is when the OIDL call style is defined in the IDL speci­fication. OIDL does not support the Environment and the Context parameters. Therefore there will no Environment and Context parameters when the call style is OIDL. The cal1 style is specified in the implementation section of the IDL using the callstyle modifier. If you use callstyle=oidl, then the method will not include the Environment and the Context parameters.

C++ Language Binding Syntax
Now, let's look at the syntax for a C++ client. The following shows the C++ frag­ment for invoking the print method on the object mybook. mybook->print(ev, 10); This syntax resembles the normal C++ invocation syntax. An invocation to a method defined in IDL requires at least one argument for the Environment structure, except when OIDL style is used.If the method includes a context spec­ification, a Context parameter must be specified after the Environment argu­ment. This is followed by the remaining arguments from the method declaration.

Note that the CORBA 1.1 specification does not include a C++ Language Map­ping. However, OMG is in the process of standardizing a C++ Language Mapping for CORBA 2.0. Future releases of SOM are expected to comply with the C++ Language Mapping.

Getting Started
To run the programs described in this book, you need to have the following prod­ucts installed: All the programs in this book are written using the SOM 2.0 Toolkit for OS/2 and the IBM C Set++ 2.1 products. The source code for the programs can be found on the utilities disk in the back of this book so that you can make modifications. If you are interested in using SOM on AIX or Windows, you can still use most of the material in this book. In particular, all of the SOM objects are portable. The exceptions are the Graphical User Interface (GUI) code, which uses Presentation Manager primitives, and the makefiles. You can consult the SOMobjects Developer User's Guide for details on how to create makefiles for AIX and Windows. TCP/IP is only required for the Replication SOM example. You can run all the other examples without TCP/IP installed.
 * OS/2 2.1
 * C Set++ 2.1
 * OS/2 2.1 Developer's Toolkit
 * SOMobjects Developer Toolkit Version 2.0 for OS/2
 * TCP/IP Version 2.0 (optional)

Environment Setup
After you install the SOMobjects Toolkit, you need to decide whether you want to program using C++ or C. If you want to program using C++, run the somxh com­mand to generate the C++ binding files for the classes supplied with the SOMob­jects Toolkit.

If you want to program using C, there are two forms of C bindings. You will need to select one. The first form is the strict CORBA-compliant form, in which * is not exposed in object references. The second form is compatible with the OIDL in SOM 1.0, where * is visible in object references. For example, to declare an instance of class Foo, you would code either Foo afoo; 	/* CORBA-compliant form */ or Foo *afoo; 	/* OIDL-compatible form */ As the name suggests, the CORBA-compliant form allows clients to access your objects using the CORBA C Language Mapping. This might be more appropriate if your objects intend to be ported to other platforms that support the CORBA standard. The OIDL-compatible form might be more suitable if you plan to move your C to C++ implementations at some future point, because the C++ imple­mentations use * in the object references.

If you choose the CORBA-compliant form, then run the somcorba command to generate the C binding files.

If you choose the OIDL-compatible form, then run the somstars command to generate the C binding files. Also, you need to set the environment variable SMADDSTAR: set SMADDSTAR=1 You might want to use both C++ and C bindings in your application develop­ment. In this case, you will need to run somxh and either somcorba, or som­stars.

However, if you want to switch between the two C coding styles, you will need to re-run the appropriate command, set, or remove, the SMADDSTAR variable, and then manually convert all the C code that you have written to the other style. This can be a tedious process, so it is advisable to stick to one C coding style.

If you are a new SOM user, then it is recommended that you use somcorba for C and somxh for C++.

Conventions Used in this Book
All the samples that are built in this book will use IDL. The call style will be the CORBA style. Therefore, all the methods will require an Environment argu­ment. We will not use any OIDL.

You will notice that some of the SOM methods do not require an Environ­ment argument. This is because they have to be compatible with the previous release of SOM.

Most of the implementation will be done using the C++ bindings. The are two reasons for this choice:
 * 1) The C++ syntax is clearer.
 * 2) All the examples in the SOM manuals are presented in C. Therefore, to be a valuable reference for programmers, I have chosen to use C++ so that pro­grammers can compare the two.

Occasionally, I use C to illustrate the language neutral aspect of SOM. In this case, I will use the CORBA-compliant C bindings.