This section describes design issues for object classes.
The design of an object class includes the creation of the object references that clients use to refer to objects of the class. These object references are created by a class associated with the server. See the topic Object References for a detailed discussion.
The terms client and server refer to roles played by processes, but the same process can be both a client and server. When a process is invoking methods on an object, it is acting in the role of a client; when it receives method requests, it is acting in the role of a server. If you are writing a program that acts in both of these roles, you should read the considerations for both component types.
See the detailed discussions in the topics Developing Client Applications and Developing Server Applications.
This secton discusses the following:
When designing object classes for the NonStop DOM environment, you must consider several major issues, including the following:
The resoulution of issues such as these depends on the object reference that is created and returned for an object, the strategy for finding and creating object instances, and other aspects of class design and use.
The following three-tier classification of objects is not specific to NonStop DOM but is used throughout this section.
These are conceptual classifications; neither CORBA nor NonStop DOM defines specific classes to correspond to these types of objects.
In general, an interface object can interact with control or entity objects. In an OLTP environment, the user usually interacts with an interface object, which in turn interacts with a control object to initiate a transaction. The control object interacts with one or more entity objects to perform the transaction. Transactions are almost always performed against more than one database, or at least more than one database record, so interface objects seldom interact directly with entity objects.
There are no special considerations for interface objects in NonStop DOM.
Control objects do not interact with a database directly. Rather they interact with (or coordinate) entity objects, which represent and manipulate the data.
In some cases, a control object implements a whole transaction and is therefore responsible for beginning and committing that transaction.
In other cases, several control objects implement different parts of a transaction. In such cases, another control object should be defined to coordinate the work (and begin and commit the transaction).
Because a control object does not exist outside a business transaction, it does not pose the same types of object-sharing problems as objects representing shared-data resources.
However, designers must consider other issues if the object will be implemented in a server pool--specifically, whether the object needs to maintain dynamic context between calls. For example, a method that debits an account can use an account--number parameter to get all the context it needs from a database and does not have to retain dynamic state. A method that iterates through a result set will have to maintain dynamic state in the form of a "cursor" for the result set. Whether an object maintains dynamic context between calls has implications for load balancing, and therefore for application throughput, as described in Parallel Processing and Its Implications.
An entity object typically represents stored data, although it could also represent a device. Entity objects can be used by either interface objects or control objects: an interface object need not always use a control object for access to an entity object.
Entity objects are typically shared by multiple clients, usually control objects, so the application designer must expect and prepare for concurrent invocations of the same object by multiple clients.
An entity object does not typically control other entity objects. The exception occurs when an entity object is a composite of several other entity objects; for example a "customer" object could consist of basic customer information from one entity object and transaction history from another.
An object need not be persistent to represent persistent data.
The client programmer need not know whether an object is local or remote, as long as the application and class library have been designed with local/remote transparency in mind. However, object distribution has implications for application performance.
If possible, design and distribute your objects according to the following guidelines:
If a control object has many interactions with an entity object (for example, doing a linear search of many entity objects) and the control object has a few well-defined interfaces to an interface object, place the control object on the same machine as the entity object.
Likewise, if a control object uses a database directly, you should locate the object on the same machine as the database.
Design both data and methods so that interactions with remote objects require as few messages as possible. (This approach also benefits performance when the target object is local, although not as dramatically.)
For example, if a control or entity object returns an object consisting of many "readonly" attributes to a client, consider returning a struct instead. The get_ methods for accessing attributes are translated into individual network messages, whereas structs are passed by value as part of the method invocation that returns them.
The following example shows an object definition with multiple attributes:
interface account {
readonly attribute string CustomerName;
readonly attribute string CustomerAddress;
}
|
If this type of object is distributed, the client must send a separate message to read each attribute.
If the interface definition is changed to have one attribute, the client can send one message to get all the information:
interface account {
struct CustomerRecord {
string name;
string address;
};
readonly attribute CustomerRecord customer;
}
|
NonStop DOM can run application servers as NonStop TS/MP server pools. This style of implementation allows many processes to act as one logical server; each new unit of work goes to the least busy process in the pool. Server processes can run in different CPUs to allow for parallel processing. See the Administration Guide for details on server pools.
In general, the implementation of an object in a server pool is transparent to the programmer except for the following characteristics:
In NonStop DOM, objects can be either stateful or stateless.
If an object is stateless, each method invocation for the object can be handled by a different server process in the pool. A stateless object cannot maintain state information in memory between calls, because the state information would be available to only one process.
If an object is stateful, the first method invocation for the object goes to any free server process in the pool, and any subsequent requests go to that same process. A stateful object can maintain state information in memory between method invocations, because only one process needs access to the information.
The same server pool can host both stateless and stateful objects. The distinction between stateless and stateful is made regardless of whether the object is in a server pool or in a dedicated single server.
From an ORB method-routing viewpoint, stateless requests are much more efficient than stateful requests because of the queuing efficiency that NonStop TS/MP can provide (analogous to a single line for all bank tellers rather than one line per bank teller). This factor makes it attractive to design classes to be stateless to maximize throughput.
However, in some cases, it would be inconvenient or costly for an object to be stateless. For example, if an object returns the results of a large SQL query to a client using a "cursor," the client must make multiple method invocations on the server. If the object is stateless, subsequent method invocations could reach different server processes, each of which would have to repeat the original query.