Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Web Development

Distributed Objects and the Internet


MAR96: Distributed Objects and the Internet

John is founder and principal software architect of Secant Technologies. He can be contacted at [email protected].


Many articles in DDJ and elsewhere have discussed distributed objects and the Internet, but most have been conceptual in nature (see, for example, "Networking Objects with CORBA," by Mark Betz, DDJ, November 1995). In this article, I'll discuss a real-world implementation of distributed-object technology called "LISA," short for "Leasing Information and Service Assistant." LISA is a client/server, object-oriented property-management application that automates many of the day-to-day details of managing thousands of rental properties throughout Ohio and Michigan. The LISA system comprises an OS/2 Presentation Manager app, daily processing programs, a set of Distributed System Object Model (DSOM) object services, a TCP/IP network, and more than 60 Oracle database servers.

We developed LISA for Associated Estates Realty Corp., a real-estate investment trust that stipulated the following business requirements:

  • Keep track of the suite, lease history, status, prior and present employers, prior addresses, and credit information of each resident.
  • Manage the status, lease history, and features of each suite.
  • Record the time and date of each prospective tenant's visits, their current addresses, and how they found out about the available suite (drive-by, newspaper, magazine, or whatever).
  • If a prospect agrees to rent a suite, enter the application into the system and transfer it to the credit department at the main office. The application results, notes, and requests for additional information (which are generated at the main office) must be transferred back to the site where the application originated.
  • Replicate all resident, suite, prospect, and visit information recorded at the individual properties in the central database at the main office. This database is used in marketing-analysis tasks to determine where to apply advertising resources.
  • Maintain a to-do list to remind property managers of events such as promised follow-up calls, resident-satisfaction calls, lease expirations, thank-you cards, and application results.
  • Print legal documents such as leases, applications, and attachments, as well as a large list of reports.
  • Maintain details of user logins and the hours during which the leasing offices are open.
  • Maintain high configurability. Since it is used in different cities and states, the system must comply with the law in all of these areas.
  • Use Oracle 7, the corporate standard, as the database.
Clearly LISA is a complex system. In addition to familiar problems involving user interfaces, operating systems, and development environments, LISA introduces new challenges: object services for distributed objects, naming, event notification, workflow, concurrency control, and Internet connection. In this article, I'll focus on two of these areas--distributed-object and internet-connection services--and how they relate to the three most important aspects of communications between the sites:

  • Connecting the main office to one or more of the 60+ remote properties on demand.
  • The mechanics of data communications between two sites, including the means of queueing messages when the two are not connected.
  • Exchanging complex business objects and workflow-task data. In other words, "flattening" objects into a form that can be sent over the network.

The Client Application

On the client side, LISA is an OS/2 PM application written using Borland C++ for OS/2. We used a notebook paradigm common with many OS/2 CUA-91 applications to make the application easy for nontechnical users.

Each page of this notebook lists items such as prospects, residents, and suites. An easy-to-use search facility searches for items and returns results in a list. To edit a particular item, the user simply double clicks on the desired item in the list.

The application style follows the CUA-91 guidelines. All list entries support context menus, icons, usage emphasis, and drag and drop. Full context-sensitive help is available from every part of the application via the F1 key or the help menu.

To build LISA, we employed object-modeling techniques and software layering to maximize reuse and achieve high maintainability. Figure 1 illustrates the software-component layers.

The application's foundation is built on ObjectPM, an application framework that we wrote. ObjectPM is an OS/2 C++ class library which presents OS/2's GUI, graphics, and multitasking as a set of easy-to-use software components. Other classes included in the foundation layer manage database access, workflow, and reporting. The business and configuration model classes are built on top of this base.

The business model and foundation classes are combined in the application layer to form the finished application. The application layer consists of a set of GUI and application-level classes used to glue the reusable components underneath. This layer is relatively thin compared to the final assembly, representing less than one-third of the code.

Overall System Organization

Figure 2 illustrates the global structure of the LISA system. The main AERC office houses a backbone network supporting NetWare, DecNet, and TCP/IP. The principal Oracle database is housed in a Compaq Proliant SMP computer with two 100-MHz Pentium processors running OS/2 SMP 2.1. This machine also runs a number of DSOM object services that handle event management, naming, properties, workflow routing, and concurrency control for all LISA clients on the LAN.

Outside the main office, more than 60 properties run the LISA system. Each site has between one and four computers, depending on the size of the property. If there is only one machine, then all software--including Oracle, the object services, and applications--must run on this machine. For larger properties with more computers, the OS/2 peer services are used to share disk and printer resources among users.

The main office and individual properties connect on an intermittent basis using a TCP/IP point-to-point connection service implemented as a DSOM object service. This server maintains a catalog of remote networks and their Internet addresses. When a user or processing program needs to contact a distant network, it finds the connection-service object and invokes the connect method on it, supplying the name of the desired network. The connection service responds by dialing the modem and waiting for the receiver to answer. When the remote site answers, both sides exchange addresses, launch a TCP/IP PPP driver, and configure the IP routing tables to join the two networks.

Some remote properties are large enough to warrant full-time connections to the main office. These properties are equipped with an ISDN connection to a frame relay network at the phone company. The main office is also connected to this network. The connection service needn't worry about these sites since they are online all the time.

The main office and each property are connected at least once a day to exchange and update information. Users at the main office dial into a property to connect with the local database. Since each Oracle server can be connected through the TCP/IP network, users on one network can easily use databases from other networks to perform queries and maintain the system.

Distributed-Object Services

LISA's client/server architecture uses an Oracle database server in addition to the other servers used for workflow, synchronization, and moving information throughout the system. These servers were written in C++ using the MetaWare High C/C++ compiler with Direct-to-SOM (DTS) support. This allowed us to write a set of SOM-based classes in native C++, and to make objects created from these classes accessible to remote clients over the network.

Figure 3 shows the basic idea of distributed objects. The (sharable) objects run in a process called a "DSOM server." To use the object, a client finds the object through the Object Request Broker (ORB), which returns a "proxy" object. As far as the client application is concerned, the proxy appears and works like any other local object. However, when the client invokes a method on the proxy, the ORB intercepts the method request and forwards the request (along with the calling arguments) to the server that contains the real object. The server then locates the object, invokes the operation, and sends back the return value(s).

IBM's System Object Model (SOM) provides an object manager that allows object-oriented functionality--defining classes, creating objects, and invoking methods--outside the bounds of a specific programming language. In other words, it provides the features of an object-oriented language (such as Smalltalk or C++) without the language. SOM hides the implementation details of a class from a program that uses it. For example, a SOM class library can be coded in C++, then used by a Smalltalk program.

DSOM, a natural extension of SOM, also is an implementation of OMG's Common Object Request Broker Architecture (CORBA), which defines the standard for distributed-object technology and services. DSOM and CORBA extend the idea of separating an object's client and implementation with "location transparency." This means that a client can use an object without knowing where it's physically located. Thus, objects can be located around a network and used by client applications just as though they were located in the same process as the client. This allows implementation of custom servers as distributed objects. Figure 4 illustrates the object services used by LISA. Each distributed service is a general-purpose software component that provides service to all LISA clients on the network.

The distributed-object facility implements communication between clients and servers, as well as between remote properties. Unlike the classical communications model, which sends raw messages to a distant socket, this approach is easier to use, more robust, and allows the message data to be structured in the form of calling arguments. It also hides the actual communications transport and the details of low-level socket and IPC programming.

Property Sets and Sonics

All object services use a common set of data-management structures. The first, a PropertySet, is a block of memory that contains a collection of name-value pairs. For instance, Example 1 is a property set that contains an address. The PropertySet class contains methods to add, remove, query, and change these name-value pairs.

PropertySets also can contain any CORBA datatype, including blobs, data streams, and other PropertySets. Furthermore, there are no pointers in the PropertySet, which allows PropertySets to be sent from process to process (via DSOM method calls and event channels). Thus a PropertySet is a mobile, mutable data object with many uses. In one way, it is used to get around the CORBA limitation of not allowing objects to be copied by value between the client and server. If an object is passed as a parameter to a remote method call, for example, its reference is marshaled and converted to a proxy object at the server. CORBA does not support passing objects by value.

With a PropertySet, you can flatten one or more objects into a stream in memory using the Object Externalization Service, and place that block of memory containing the object(s) in the PropertySet with a given name. The memory block can then be used as a calling argument or return value to a DSOM method call (since a PropertySet possesses the same structure as a CORBA sequence). The receiving process can get the object(s) by extracting the block of memory from the PropertySet and then using the Internalization Service to convert the stream back into objects.

Persistence Services

Persistence is an important aspect of managing the LISA data model. More specifically, we must be able to store and retrieve business objects to and from an Oracle 7 database and memory-based streams. To solve the problem of object persistence, LISA business classes were defined and implemented using our Persistent Object Manager (POM). This tool, an enhanced implementation of the Persistence Service defined by the Object Management Group (OMG), includes both a precompiler for reading object definitions and a run-time persistence engine that handles the mechanics of object storage. The basic idea is that the precompiler reads a set of class definitions and produces a schema, which is used to automatically store and retrieve the business objects to and from the database. As far as the application is concerned, Oracle functions as an object database. Figure 5 illustrates the architecture of the persistence service.

Like the LISA application itself, the persistence service is built in layers. The top layer, POM, provides a virtual object-database interface to the application. All I/O requests, queries, and transaction operations are submitted to POM. The next layer, the Persistent Data Service (PDS), contains the bulk of the persistence engine. It is responsible for creating, reading, and writing the business objects, and interfacing with the I/O drivers. The bottom layer is composed of media drivers that accept the I/O requests from the PDS and translate them into data-manipulation operations for a specific data store (such as Oracle or I/O streams).

The fundamental idea of the persistence service is to provide a common interface to all types of data stores for object-oriented applications. Technologies such as file storage, streams, relational databases, and even object databases are presented in a common way. This has been the result of the work done by OMG and the Object Database Management Group (ODMG) consortia to standardize database and transaction management.

In terms of communications, POM is a key component used to externalize the business objects exchanged between the main office and the remote sites. The Externalization Service is a simple class that uses the stream driver of POM to write and read complex business objects into PropertySets. These PropertySets, as described earlier, are sent to the receiver via method calls on distributed objects.

Internet Connection Service

The Internet Connection Service (ICS) is a DSOM object service that plays two important roles in the LISA system. First and foremost, it is responsible for connecting and disconnecting remote TCP/IP networks from the calling network on demand. It also must monitor these connections and restart the connection if the system encounters trouble. The second purpose of this service is to orchestrate the transfer of event and workflow data between two networks.

To develop such a service, you need to first design the interface (operations) of the service and then define it using the Interface Definition Language (IDL). Listing One shows the IDL definition of the ICS. This file is compiled by the SOM IDL compiler, which generates the SOM class tables, headers, and C++ method templates. From there, the service is completed by implementing the methods and building native C++ class equivalents of the structures defined in the IDL file.

The service itself is compiled, linked into a DLL and executed by the DSOM run time. We generally start this service when the machine boots, then leave it running all the time. When it initializes, it reads a configuration file that contains the catalog of remote network names, phone numbers, protocols, and IP addresses. Once initialized, these networks can be connected and disconnected on demand via the object-service methods.

When the client application starts up, it gets a list of the available distant networks by invoking the list_networks method on the ICS object. This method returns a collection of NetworkDef objects that the application uses to initialize the Connect menu. Users choose an item from this menu when they want to connect to the Oracle database at that property. When this occurs, the ICS is used to establish the connection (if not done already) and return a handle that we can use to close the connection when we're finished with it. Listing Two is a code fragment used to interact with the ICS to accomplish connection and disconnection.

As Listing Two shows, using an object service first involves acquiring a proxy to the server object by invoking the somdFindServerByName method on the DSOM object manager. When remote methods are invoked that return an object either as a return value or out parameter, proxy objects are created by DSOM. Once a proxy is returned, it is used like any other object. The application doesn't know if the object is local or remote.

Conclusion

Thanks to object technology, LISA can and will grow for a long time. The key to long-term maintainability lies in the ability to modularize. We do this by using objects that are software modules that hide their data and implementation from each other. This eliminates many of the dependencies inherent in traditional programs and allows updates to these modules without upsetting the whole system.

These concepts are applied to the client/server components of the system as well. Each "server" is a set of one or more distributed objects that provide general-purpose services without disclosing the details of how the services were implemented or where they exist. This allows them to be moved, extended, or even completely rewritten in another language without breaking binary compatibility.

Figure 1: System component layers.

Figure 2: LISA system structure.

Figure 3: Distributed objects.

Figure 4: Distributed object services.

Figure 5: Object persistence services.

Example 1: Typical property set.

Property Name          Type     Value

"Street"          tc_STRING     "220 Center St."
"City"            tc_STRING     "Mentor"
"State"           tc_STRING     "OH"
"ZipCode"         tc_LONG       44060

Listing One

// file: connctsv.idl
#include <somobj.idl>
struct TimeStamp;
enum NPConnectStatus 
{ 
    NPConnected, 
    NPDisconnected, 
    NPTrying 
};
// structure to define a TCP/IP interface
struct NetworkPort
{
    unsigned long handle;
    string port_name;
    string attached_network;
    NPConnectStatus status;
    unsigned short connections;
    long last_error;
    long last_drverror;
};
// defines a typed array of NetworkPort structures
typedef sequence <NetworkPort> NetworkPortList;
// structure definition for specific connection
struct NetConnection
{
    string port_name;
    HConnect hcnct;
    string user_name;
    string user_host;
    TimeStamp connectTime;
};
typedef sequence <NetConnection> NetConnectionList;
typedef sequence<string> TelephoneNumberList;
struct NetworkDef;
{
    string netname;
    unsigned long address;
    string description;
    TelephoneNumberList phoneNumbers;
    string setup;
};
typedef sequence <NetworkDef> NetworkList;
// exceptions
exception ctsvException
{
    long errorCode;

    long driverCode;
};
// Internet Connection Service interface (class) definition
interface ConnectService : SOMDServer
{
    HConnect connect(in string network) raises(ctsvException);
    void disconnect(in HConnect hcnct) raises(ctsvException);
    boolean is_connected(in string network) raises(ctsvException); 
    void exchange_events(in HConnect hcnct) raises(ctsvException);
    NetworkPort get_port(in HConnect hcnct) raises(ctsvException);
    unsigned short get_port_count();
    void list_ports(out NetworkPortList ports);
    void list_connections(out NetConnectionList cncts);
    void list_networks(out NetworkList nets);
    #ifdef __SOMIDL______LINEEND____
    implementation
    {
        releaseorder : connect, disconnect, is_connected, 
            exchange_events, get_port, get_port_count, 
            list_ports, list_connections, list_networks;
        callstyle=idl;
        dllname = "ctserv.dll";
        memory_management = corba;
        majorversion = 1;
        minorversion = 0;
        somDefaultInit: override, init;
        somDestruct: override;
    };
    #endif
};

Listing Two

void 
LISAAppFrame :: ConnectNetwork(NetworkDef *net, LISAEnv *appl)
{
    Environment *ev = __SOMenv;
    // obtain a proxy object to the ICS by asking DSOM for the service by its
    // alias name. (defined when the server was installed in the system)
 
    ConnectService *ctsv = (ConnectService *)   
        SOMD_ObjectMgr->somdFindServerByName(ev, "connectService");
    if (!ev->OK())
        throw CORBA::SystemException(ev);
    // now that have the server object, initiate the connection:
    HConnection handle = ctsv->connect(ev, net->netname);
    if (ev->OK())
    {
        // network connection established OK, now attempt Oracle logon 
        // connection. First, build the Oracle SQL*Net connection
        // string: "userid/password@t:netname"
        char signOn[80];
        sprintf(signOn, "%s/%s@t:%s", appl->user, 
            appl->password, net->netname);
        try
        {
            // connect the the database via the persistence driver
            appl->oracleDb->Connect(signon);
            // Done!  Save the connection handle and return
            appl->hConnect = handle;
        }
        catch(...)
        {
            // No go. Either the database is down or the user does not have
            // permission to access the database. Cancel the connection to the
            // remote network and return the error to the caller.
            ctsv->disconnect(ev, handle);
            throw;
        }
    }
    else
        throw CORBA::SystemException(ev);
}
void 
LISAAppFrame :: DisconnectNetwork(LISAEnv *appl)
{
    Environment *ev = __SOMenv;
    // connect the the database via the persistence driver
    appl->oracleDb->Disconnect();
    // obtain a proxy object to the ICS from DSOM
    ConnectService *ctsv = (ConnectService *)   
        SOMD_ObjectMgr->somdFindServerByName(ev, "connectService");
    if (!ev->OK())
        throw CORBA::SystemException(ev);
    // now that we have the server object, destroy the connection:
    ctsv->disconnect(ev, appl->hConnect);
    appl->hConnect = NULLHANDLE;
}


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.