![]() |
![]() |
![]() |
![]() |
![]() |
Each of the chapters in this book gives procedures for and examples of building CORBA server applications that take advantage of various Oracle Tuxedo software features. For background information about Oracle Tuxedo CORBA server applications and how they work, see Getting Started with Oracle Tuxedo CORBA Applications.There are also a number of files that you work with that are generated by the IDL compiler and that you build into a CORBA server application. These files are listed and described in Chapter 2, “Steps for Creating an Oracle Tuxedo CORBA Server Application.”The sections that follow provide introductory information about these entities. For complete details about how to generate these components, see Chapter 2, “Steps for Creating an Oracle Tuxedo CORBA Server Application.”For more information about OMG IDL, see Creating CORBA Client Applications.Client applications access and manipulate the CORBA objects managed by the server application via object references to those objects. Client applications invoke operations (that is, requests) on an object reference. These requests are sent as messages to the server application, which invokes the appropriate operations on CORBA objects. The fact that these requests are sent to the server application and invoked in the server application is completely transparent to the client; client applications appear simply to be making invocations on the client stub.Typically, object references to CORBA objects are created in the Oracle Tuxedo system by factories. A factory is any CORBA object that returns, as one of its operations, a reference to another CORBA object. You implement your application’s factories the same way that you implement other CORBA objects defined for your application. You can make your factories widely known to the Oracle Tuxedo domain, and to clients connected to the Oracle Tuxedo domain, by registering them with the FactoryFinder. Registering a factory is an operation typically performed by the Server object, which is described in the section “The Server Object” on page 1‑7. For more information about designing factories, see the section “Generating Object References” on page 1‑8.
• The group ID identifies the server group to which the object reference is routed when a client application makes a request using that object reference. Generating a nondefault group ID is part of a key Oracle Tuxedo feature called factory-based routing, which is described in the section “Factory-based Routing” on page 8‑11.For more information about factory-based routing, see the section “Factory-based Routing” on page -11.An object reference created with the TP::create_active_object_reference() operation is valid only for the lifetime of the server process in which it was created. For more information, see the section “Preactivating an Object with State” on page 3‑15.When a server application receives a request for an object that is not mapped in the server machine’s memory (that is, the object is not active), the TP Framework invokes the Server::create_servant()operation. The Server::create_servant()operation is implemented in the Server object, which, as mentioned in the section “The Implementation of the CORBA Objects for Your Server Application” on page 1‑2, is a component of a CORBA server application that you create.The Server::create_servant()operation causes an instance of the CORBA object implementation to be mapped into the server machine’s memory. This instance of the object’s implementation is called the object’s servant. Formally speaking, a servant is an instance of the C++ class that implements an interface defined in the application’s OMG IDL file. The servant is generated via the C++ new statement that you write in the Server::create_servant()operation.After the object’s servant has been created, the TP Framework invokes the Tobj_ServantBase::activate_object() operation on the servant. The Tobj_ServantBase::activate_object() operation is a virtual operation that is defined on the Tobj_ServantBase base class, from which all object implementation classes inherit. The TP Framework invokes the Tobj_ServantBase::activate_object() operation to tie the servant to an object ID (OID). (Conversely, when the TP Framework invokes the Tobj_ServantBase::deactivate_object() operation on an object, the servant’s association with the OID is broken.)If your object has data on disk that you want to read into memory when the CORBA object is activated, you can have that data read by defining and implementing the Tobj_ServantBase::activate_object() operation on the object. The Tobj_ServantBase::activate_object() operation can contain the specific read operations required to bring an object’s durable state into memory. (There are circumstances in which you may prefer instead to have an object’s disk data read into memory by one or more separate operations on the object that you may have coded in the implementation file. For more information, see the section “Reading and Writing an Object’s Data” on page 1‑14.) After the invocation of the Tobj_ServantBase::activate_object() operation is complete, the object is said to be active.Servant pooling provides your CORBA server application the opportunity to keep a servant in memory after the servant’s association with a specific OID has been broken. When a client request that can be satisfied with a pooled servant arrives, the TP Framework bypasses the TP::create_servant operation and creates a link between the pooled servant and the OID provided in the client request.Servant pooling thus provides the CORBA server application with a means to minimize the costs of reinstantiating a servant each time a request arrives for an object that can be satisfied by that servant. For more information about servant pooling and how to use it, see the section “Servant Pooling” on page 2‑25.
• Performing basic server application initialization operations, which may include registering factories managed by the server application and allocating resources needed by the server application. If the server application is transactional, the Server object also implements the code that opens an XA resource manager.You create the Server object from scratch, using a common text editor. You then provide the Server object as input into the server application build command, buildobjserver. For more information about creating the Server object, see Chapter 2, “Steps for Creating an Oracle Tuxedo CORBA Server Application.”
• The Bootstrap object
• Factories managed in the Oracle Tuxedo domainClient applications use the Bootstrap object to resolve initial references to a specific set of objects in the Oracle Tuxedo domain, such as the FactoryFinder and the SecurityCurrent objects. The Bootstrap object is described in Getting Started with Oracle Tuxedo CORBA Applications and Creating CORBA Client Applications.While an object associated with a conventional object reference is not instantiated until a client application makes an invocation on the object, the object associated with an active object reference is created and activated at the time the active object reference is created. Active object references are especially convenient for specific purposes, such as iterator objects. The section “Preactivating an Object with State” on page 3‑15 provides more information about active object references.In an Oracle Tuxedo domain, object state refers specifically to the process state of an object across client invocations on it. The Oracle Tuxedo software uses the following definitions of stateless and stateful objects shown in Table 1‑1:
Table 1‑1 About Object State
• The object invokes the TP::deactivateEnable() operation on itself.State management also involves how long an object remains active, which has important implications on server performance and the use of machine resources. The duration of an active object is determined by object activation policies that you assign to an object’s interface, described in the section that follows.To achieve optimal application performance, you need to carefully plan how your application’s objects manage state. Objects are required to save their state to durable storage, if applicable, before they are deactivated. Objects must also restore their state from durable storage, if applicable, when they are activated. For more information about reading and writing object state information, see the section “Reading and Writing an Object’s Data” on page 1‑14.
Note:
Table 1‑2 Object Activation Policies The method activation policy is associated with stateless objects. This activation policy is the default. For more information about object behavior within the scope of a transaction, and general guidelines about using this policy, see Chapter 6, “Integrating Transactions into a CORBA Server Application.”The transaction activation policy is associated with stateful objects for a limited time and under specific circumstances.
• An operation on this object invokes the TP::deactivateEnable() operation, which causes this object to be deactivated. (This is part of a key Oracle Tuxedo feature called application-controlled deactivation, which is described in the section “Application-controlled Deactivation” on page -13.An object with this activation policy is called a process-bound object. The process activation policy is associated with stateful objects.You determine what events cause an object to be deactivated by assigning object activation policies. For more information about how you assign object activation policies to an object’s interface, see the section “Step 4: Define the In-memory Behavior of Objects” on page 2‑13.The Oracle Tuxedo software also provides a feature called application-controlled deactivation, which provides a means for an application to deactivate an object during run time. The Oracle Tuxedo software provides the TP::deactivateEnable() operation, which a process-bound object can invoke on itself. When invoked, the TP::deactivateEnable() operation causes the object in which it exists to be deactivated upon completion of the current client invocation on that object. An object can invoke this operation only on itself; you cannot invoke this operation on any object but the object in which the invocation is made.
Note: If you use application-controlled deactivation to implement a conversational model between a client application and an object managed by the server application, make sure that the object eventually invokes the TP::deactivateEnable() operation. Otherwise, the object remains idle in memory indefinitely. (Note that this can be a risk if the client application crashes before the TP::deactivateEnable() operation is invoked. Transactions, on the other hand, implement a timeout mechanism to prevent the situation in which the object remains idle for an indefinite period. This may be another consideration when choosing between the two conversational models.)
1. In the implementation file, insert an invocation to the TP::deactivateEnable() operation at the appropriate location within the operation of the interface that uses application-controlled deactivation.
2. In the Implementation Configuration File (ICF file), assign the process activation policy to the interface that contains the operation that invokes the TP::deactivateEnable() operation.
3. Many of the CORBA objects managed by the server application may have data that is in external storage. This externally stored data may be regarded as the persistent or durable state of the object. You must address durable state handling at appropriate points in the object implementation for object state management to work correctly.Table 1‑3 and Table 1‑4 describe the available mechanisms for reading and writing an object’s durable state.
After the TP Framework creates the servant for an object, the TP Framework invokes the Tobj_ServantBase::activate_object() operation on that servant. As mentioned in the section “How You Instantiate a CORBA Object at Run Time” on page 1‑6, this operation is defined on the Tobj_ServantBase base class, from which all the CORBA objects you define for your client/server application inherit.You may choose not to define and implement the Tobj_ServantBase::activate_object() operation on your object, in which case nothing happens regarding specific object state handling when the TP Framework activates your object. However, if you define and implement this operation, you can choose to include code in this operation that reads some or all of an object’s durable state into memory. Therefore, the Tobj_ServantBase::activate_object() operation provides your server application with its first opportunity to read an object’s durable state into memory.Note that if an object’s OID contains a database key, the Tobj_ServantBase::activate_object() operation provides the only means the object has to extract that key from the OID.For more information about implementing the Tobj_ServantBase::activate_object() operation, see “Step 2: Write the Methods That Implement Each Interface’s Operations” on page 2‑5. For an example of implementing the Tobj_ServantBase::activate_object() operation, see Chapter 3, “Designing and Implementing a Basic CORBA Server Application.”
When an object is being deactivated by the TP Framework, the TP Framework invokes this operation on the object as the final step of object deactivation. As with the Tobj_ServantBase::activate_object() operation, the Tobj_ServantBase::deactivate_object() operation is defined on the Tobj_ServantBase class. You implement the deactivate_object() operation on your object optionally if you have specific object state that you want flushed from memory or written to a database.The Tobj_ServantBase::deactivate_object() operation provides the final opportunity your server application has to write durable state to disk before the object is deactivated.If your object keeps any data in memory, or allocates memory for any purpose, you implement the Tobj_ServantBase::deactivate_object() operation so your object has a final opportunity to flush that data from memory. Flushing any state from memory before an object is deactivated is critical in avoiding memory leaks. For method-bound and process-bound objects in general, you typically perform database write operations within these operations and not in the Tobj_ServantBase::deactivate_object() operation.For transaction-bound objects, however, writing durable state in the Tobj_ServantBase::deactivate_object() operation provides a number of object management efficiencies that may make sense for your transactional server applications.
Note: If you use the Tobj_ServantBase::deactivate_object() operation to write any durable state to disk, any errors that occur while writing to disk are not reported to the client application. Therefore, the only circumstances under which you should write data to disk in this operation is when: the object is transaction-bound (that is, it has the transaction activation policy assigned to it), or you scope the disk write operations within a transaction by invoking the TransactionCurrent object. Any errors encountered while writing to disk during a transaction can be reported back to the client application. For more information about using the Tobj_ServantBase::deactivate_object() operation to write object state to disk, see the section “Caveat for State Handling in Tobj_ServantBase::deactivate_object()” on page 2‑25.Using the Tobj_ServantBase::activate_object() operation on an object to read durable state may be appropriate when either of the following conditions exist:The advantages of using the Tobj_ServantBase::activate_object() operation to read durable state include:With all objects, regardless of activation policy, you can read durable state in each operation that needs that data. That is, you handle the reading of durable state outside the Tobj_ServantBase::activate_object()operation. Cases where this approach may be appropriate include the following:
• For example, consider an object that represents a customer’s investment portfolio. The object contains several discrete records for each investment. If a given operation affects only one investment in the portfolio, it may be more efficient to allow that operation to read the one record than to have a general-purpose Tobj_ServantBase::activate_object() operation that automatically reads in the entire investment portfolio each time the object is invoked.In the case of stateless objects—that is, objects defined with the method activation policy—you must ensure the following:The TP Framework invokes the Tobj_ServantBase::activate_object() operation on an object at activation. If an object has an OID that contains a key to the object’s durable state on disk, the Tobj_ServantBase::activate_object() operation provides the only opportunity the object has to retrieve that key from the OID.If you have a stateless object that you want to be able to participate in a transaction, we generally recommend that if the object writes any durable state to disk that it be done within individual methods on the object. However, if you have a stateless object that is always transactional—that is, a transaction is always scoped when this object is invoked—you have the option to handle the database write operations in the Tobj_ServantBase::deactivate_object() operation, because you have a reliable mechanism in the XA resource manager to commit or roll back database write operations accurately.Servant pooling is a particularly useful feature for stateless objects. When your CORBA server application pools servants, you can significantly reduce the costs of instantiating an object each time a client invokes it. As mentioned in the section “Servant Pooling” on page -7, a pooled servant remains in memory after a client invocation on it is complete. If you have an application in which a given object is likely to be invoked repeatedly, pooling the servant means that only the object’s data, and not its methods, needs to be read into and out of memory for each client invocation. If the cost associated with reading an object’s methods into memory is high, servant pooling can reduce that cost.For information about how to implement servant pooling, see the section “Servant Pooling” on page 2‑25.
• In the case of transaction-bound objects, you can postpone writing durable state until the Tobj_ServantBase::deactivate_object() operation is invoked, when the transaction outcome is known.For more information about objects and transactions, see Chapter 6, “Integrating Transactions into a CORBA Server Application.”As mentioned in the preceding sections, you implement the Tobj_ServantBase::deactivate_object() operation as a means to write an object’s durable state to disk. You should also implement this operation on an object as a means to flush any remaining object data from memory so that the object’s servant can be used to activate another instance of that object. You should not assume that an invocation to an object’s Tobj_ServantBase::deactivate_object() operation also results in an invocation of that object’s destructor.
• Reading only the state that is common to all the operations in the Tobj_ServantBase::activate_object() operation. Defer the reading of additional state to only the operations that require it.A general optimization is to initialize a dirtyState flag on activation and to write data in the Tobj_ServantBase::deactivate_object() operation only if the flag has been changed while the object was active. (Note that this works only if you can be assured that the object is always activated in the same server process.)For examples of the sequence of activity that takes place when an object is activated, see Getting Started with Oracle Tuxedo CORBA Applications.The Process-Entity design pattern applies to a large segment of enterprise-class client/server applications. This design pattern is referred to as the flyweight pattern in Object-Oriented Design Patterns, Gamma et al., and as the Model-View-Controller in other publications.
• You can achieve the advantages of a fine-grained object model without implementing fine-grained objects. Instead, you use CORBA struct datatypes to simulate objects.An example of applying the Process-Entity design pattern is described in Chapter 3, “Designing and Implementing a Basic CORBA Server Application.” For complete details on the Process-Entity design pattern, see Technical Articles.