|
|
|
|
|
TP Framework
This topic includes the following sections:
The BEA Tuxedo CORBA TP Framework provides a programming TP Framework that enables users to create servers for high-performance TP applications. This chapter describes the TP Framework programming model and the TP Framework application programming interface (API) in detail. Additional information about how to use this API can be found in Creating CORBA Server Applications.
The TP Framework is required when developing BEA Tuxedo CORBA servers. Later releases will relax this requirement, though it is expected that most customers will use the TP Framework as an integral part of their applications.
BEA Tuxedo provides the infrastructure for providing load balancing, transactional capabilities, and administrative infrastructure. The base API used by the TP Framework is the CORBA API with BEA extensions. The TP Framework API is exposed to customers. The BEA Tuxedo ATMI is an optional API that can be mixed in with TP Framework APIs, allowing a customer to deploy distributed applications using a mix of CORBA servers and ATMI servers.
Before BEA Tuxedo CORBA, ORB products did not approach BEA Tuxedo's performance in large-scale environments. BEA Tuxedo systems support applications that can process hundreds of transactions per second. These applications are built using the BEA Tuxedo stateless-service programming model that minimizes the amount of system resources used for each request, and thus maximizes throughput and price performance.
Now, BEA Tuxedo CORBA and its TP Framework give customers a way to develop CORBA applications with performance similar to BEA Tuxedo ATMI applications. BEA Tuxedo CORBA servers provide throughput, response time, and price performance approaching the BEA Tuxedo stateless-service programming model, while using the CORBA programming model.
A Simple Programming Model
The TP Framework provides a simple, useful subset of the wide range of possible CORBA object implementation choices. You use it for the development of server-side object implementations only. When using any client-side CORBA ORB, clients interact with CORBA objects whose server-side implementations are managed by the TP Framework. Clients are unaware of the existence of the TP Framework—a client written to access a CORBA object executing in a non-BEA Tuxedo server environment will be able to access that same CORBA object executing in a BEA Tuxedo server environment without any changes or restrictions to the client interface.
The TP Framework provides a server environment and an API that is easier to use and understand than the CORBA Portable Object Adapter (POA) API, and is specifically geared towards enterprise applications. It is a simple server programming model and an orthodox implementation of the CORBA model, which will be familiar to programmers using ORBs such as ORBIX or VisiBroker.
The TP Framework simplifies the programming of BEA Tuxedo CORBA servers by reducing the complexity of the server environment in the following ways:
The TP Framework provides the following functionality:
Control Flow
The TP Framework, in conjunction with the ORB and the POA, controls the flow of the application program by doing the following:
Object State Management
The TP Framework API provides callback methods for application code to implement flexible state management schemes for CORBA objects. State management involves the saving and restoring of object state on object deactivation and activation. It also concerns the duration of activation of objects, which influences the performance of servers and their resource usage. The default duration of object activation is controlled by policies assigned to implementations at IDL compile time.
Transaction Integration
TP Framework transaction integration provides the following features:
Object Housekeeping
When a server is shut down, the TP Framework rolls back any transactions that the server is involved in and deactivates any CORBA objects that are currently active.
High-level Services
The TP interface in the TP Framework API provides methods for performing object registrations and utility functions. The following services are provided:
The purpose of these high-level service methods is to eliminate the need for developers to understand the CORBA POA, CORBA Naming Service, and BEA Tuxedo APIs, which they use for their underlying implementations. By encapsulating the underlying API calls with a high-level set of methods, programmers can focus their efforts on providing business logic rather than understanding and using the more complex underlying facilities.
State Management
State management involves the saving and restoring of object state on object deactivation and activation. It also concerns the duration of activation of objects, which influences the performance of servers and their resource usage. The external API of the TP Framework provides activate_object and deactivate_object methods, which are a possible location for state management code.
Activation Policy
State management is provided in the TP Framework by the activation policy. This policy controls the activation and deactivation of servants for a particular IDL interface (as opposed to the creation and destruction of the servants). This policy is applicable only to CORBA objects using the TP Framework.
The activation policy determines the default in-memory activation duration for a CORBA object. A CORBA object is active in a POA if the POA's active object map contains an entry that associates an object ID with an existing servant. Object deactivation removes the association of an object ID with its active servant. You can choose from one of three activation policies: method (the default), transaction, or process.
Note: The activation policies are set in an ICF file that is configured at OMG IDL compile time. For a description of the ICF file, refer to the Implementation Configuration File (ICF) section.
The activation policies are described below:
The activation of the CORBA object (that is, the association between the object ID and the servant) lasts until the end of the method. At the completion of a method, the object is deactivated. When the next method is invoked on the object reference, the CORBA object is activated (the object ID is associated with a new servant). This behavior is similar to that of a BEA Tuxedo stateless service.
The activation of the CORBA object (that is, the association between the object ID and the servant) lasts until the end of the transaction. During the transaction, multiple object methods can be invoked. The object is activated before the first method invocation on the object and is deactivated in one of the following ways:
The transaction activation policy provides a means for an object to vote on the outcome of the transaction prior to the execution of the two-phase commit algorithm. An object votes to roll back the transaction by calling Current.rollback_only() in the Tobj_ServantBase::deactivate_object method. It votes to commit the transaction by not calling Current.rollback_only() in the method.
Note: This is a model of resource allocation that is similar to that of a BEA Tuxedo conversational service. However, this model is less expensive than the BEA Tuxedo conversational service in that it uses fewer system resources. This is because of the BEA Tuxedo ORB's multicontexted dispatching model (that is, the presence of many servants in memory at the same time for one server), which makes it possible for a single server process to be shared by many concurrently active servants that service many clients. In the BEA Tuxedo system, the process would be dedicated to a single client and to only one service for the duration of a conversation.
The activation of the CORBA object begins when it is invoked while in an inactive state and, by default, lasts until the end of the process.
Note: The TP Framework API provides an interface method (TP::deactivateEnable) that allows the application to control the timing of object deactivation for objects that have the activation policy set to process. For a description of this method, see the section TP::deactivateEnable().
Application-controlled Activation and Deactivation
Ordinarily, activation and deactivation decisions are made by the TP Framework, as discussed earlier in this chapter. The techniques in this section show how to use alternate mechanisms. The application can control the timing of activation and deactivation explicitly for objects with particular policies.
Explicit Activation
Application code can bypass the on-demand activation feature of the TP Framework for objects that use the process activation policy. The application can "preactivate" an object (that is, activate it before any invocation) using the TP::create_active_object_reference call.
Preactivation works as follows. Before the application creates an object reference, the application instantiates a servant and initializes that servant's state. The application uses TP::create_active_object_reference to put the object into the Active Object Map (that is, associate the servant with an ObjectId). Then, when the first invocation is made, the TP Framework immediately directs the request to the process that created the object reference and then to the existing servant, bypassing the necessity to call Server::create_servant and then the servant's activate_object method (just as if this were the second or later invocation on the object). Note that the object reference for such an object will not be directed to another server and the object will never go through on-demand activation as long as the object remains activated.
Since the preactivated object has the process activation policy, it will remain active until one of two events occurs: (1) the ending of the process or (2) a TP::deactivateEnable call.
Usage Notes
Preactivation is especially useful if the application needs to establish the servant with an initial state in the same process, perhaps using shared memory to initialize state. Waiting to initialize state until a later time and in a potentially different process may be very difficult if that state includes pointers, object references, or complex data structures. TP::create_active_object_reference guarantees that the preactivated object is in the same process as the code that is doing the preactivation. While this is convenient, preactivation should be used sparingly, as should all process objects, because it preallocates precious resources. However, when needed and used properly, preallocation is more efficient than alternatives.
Examples of such usage might be an object using the "iterator" pattern. For example, there might a potentially long list of items that could be returned (in an unbound IDL sequence) from a "database_query" method (for example, the contents of the telephone book). Returning all such items in the sequence is impractical because the message size and the memory requirements would be too large.
On an initial call to get the list, an object using the iterator pattern returns only a limited number of items in the sequence and also returns a reference to an "iterator" object that can be invoked to receive further elements. This iterator object is initialized by the initial object; that is, the initial object creates a servant and sets its state to keep track of where in the long list of items the iteration currently stands (the pointer to the database, the query parameters, the cursor, and so forth).
The initial object preactivates this iterator object by using TP::create_active_object_reference. It also creates an object reference to that object to return to the client. The client then invokes repeatedly on the iterator object to receive, say, the next 100 items in the list each time. The advantage of preactivation in this situation is that the state might be complex. It is often easiest to set such state initially, from a method that has all the information in its context (call frame), when the initial object still has control.
When the client is finished with the iterator object, it invokes a final method on the initial object which deacativates the iterator object. The initial object deactivates the iterator object by invoking a method on the iterator object that calls the TP::deactivateEnable method, that is, the iterator object calls TP::deactivateEnable on itself.
Caution to Users
For objects to be preactivated in this fashion, the state usually cannot be recovered if a crash occurs. (This is because the state was considered too complex or inconvenient to set upon initial, delayed activation.) This is a valid object technique, essentially stating that the object is valid only for a single activation period.
However, a problem may arise because of the "one-time" usage. Since a client still holds an object reference that leads to the process containing that state, and since the state cannot be recreated after the crash, care must be taken that the client's next invocation does not automatically provoke a new activation of the object, because that object would have inapplicable state.
The solution is to refuse to allow the object to be activated automatically by the TP Framework. If the user provides the TobjS::ActivateObjectFailed exception to the TP Framework as a result of the activate_object call, the TP Framework will not complete the activation and will return an exception to the client, CORBA::OBJECT_NOT_EXIST. The client has presumably been warned about this possibility, since it knows about the iterator (or similar) pattern. The client must be prepared to restart the iteration.
Note: This defensive measure may not be necessary in the future; the TP Framework itself may detect that the object reference is no longer valid. In particular, you should not depend on the possibility that the activate_object method might be called. If the TP Framework does in fact change, activate_object will not be called and the framework itself will generate the OBJECT_NOT_EXIST exception.
Self Deactivation
Just as it is possible to preactivate an object with the process activation policy, it is possible to request the deactivation of an object with the process activation policy. The ability to preactivate and the ability to request deactivation are independent; regardless of how an object was activated, it can be deactivated explicitly.
A method in the application can request (via TP::deactivateEnable) that the object be deactivated. When TP::deactivateEnable is called and the object is subsequently deactivated, no guarantee is made that subsequent invocations on the CORBA object will result in reactivation in the same process as a previous activation. The association between the ObjectId and the servant exists from the activation of the CORBA object until one of the following events occurs: (1) the shutdown of the server process or (2) the application calls TP::deactivateEnable. After the association is broken, when the object is invoked again, it can be reactivated anywhere that is allowed by the BEA Tuxedo configuration parameters.
There are two forms of TP::deactivateEnable. In the first form (with no parameters), the object currently executing will be deactivated after completion of the method in which the call is made. The object itself makes the decision that it should be deactivated. This is often done during a method call that acts as a "signoff" signal.
The second form of TP::deactivateEnable allows a server to request deactivation of any active object, whether it is the object that is executing or not; that is, any part of the server can ask that the object be deactivated. This form takes parameters identifying the object to be deactivated. Explicit deactivation is not allowed for objects with an activation policy of transaction, because such objects cannot be safely deactivated until the end of a transaction.
In the TP::deactivateEnable call, the TP Framework calls the servant's deactivate_object method. Exactly when the TP Framework invokes deactivate_object depends on the state of the object to be deactivated. If the object is not currently in execution, the TP Framework deactivates it before returning to the caller. The object might be currently executing a method; this is always the case for TP::deactivateEnable with no parameters (since it refers to the currently executing object). In this case, TP::deactivateEnable is not told whether the object was deactivated immediately or not.
Note: The TP::deactivateEnable(interface, object id, servant) method can be used to deactivate an object. However, if that object is currently in a transaction, the object will be deactivated when the transaction commits or rolls back. If an invoke occurs on the object before the transaction is committed or rolled back, the object will not be deactivated.
To ensure the desired behavior, make sure that the object is not in a transaction or ensure that no invokes occur on the object after the TP::deactivateEnable() call until the transaction is complete.
Servant Lifetime
A servant is a C++ class that contains methods to implement an IDL interface's operations. The user writes the servant code. The TP Framework invokes methods in the servant code to satisfy requests. The servant is created by the C++ "new" statement and is destroyed by the C++ "delete" statement. Exactly who does the creation and who does the deletion, and the timing of creation and deletion, is the subject of this section.
The Normal Case
In the normal case, the TP Framework completely controls the lifetime of a servant. The basic model is that, when a request for an inactive object arrives, the TP Framework obtains a servant and then activates it (by calling its activate_object method). At deactivation time, the TP Framework calls the servant's deactivate_object method and then disposes of the servant.
The phase "the TP Framework obtains a servant" means that when the TP Framework needs a servant to be created, it calls a user-written Server method, either Server::create_servant or ServerBase::create_servant_with_id. At that time, the application code must return a pointer to the requested servant. The application almost always does this by using the C++ "new" statement to create a new instance of a servant. The phrase "disposes of the servant" means that the TP Framework removes the reference to the servant, which actually deletes it.
The application must be aware that this current behavior of always creating and removing a servant may change in future versions of this product. The application should not depend on the current behavior, but should write servant code that allows reuse of a servant. Specifically, the servant code must work even if the servant has not been freshly created (by the C++ "new" statement). The TP Framework reserves the right not to remove a servant after it has been deactivated and then to reactivate it. This means that the servant must completely initialize itself at the time of the callback on the servant's activate_object method, not at the time of servant creation (not in the constructor).
Special Cases
There are two techniques an application can use to alter the normal TP Framework use of servants. The first has to do with obtaining a servant and the second has to do with disposing of the servant.
The application can alter the "obtaining" mechanism by using explicit preactivation. In this case, the application creates and initializes a servant before asking the TP Framework to declare it activated. Once such a servant has been turned over to the TP Framework (by the TP::create_active_object_reference call), that servant is treated by the TP Framework just like every other servant. The only difference is in its method of creation and initialization.
The application can alter the "disposing" mechanism by taking the responsibility for disposing of a servant instead of leaving that responsibility with the TP Framework. Once a servant is known to the TP Framework (through Server::create_servant, ServerBase::create_servant_with_id, or TP::create_active_object_reference), the TP Framework's default behavior is to remove that servant itself. In this case, the application code must no longer use references to the servant after deactivation.
However, the application may tell the TP Framework not to dispose of the servant after the TP Framework deactivates it. Taking responsibility for a servant is done on an individual servant basis, not for a whole class of servants, by calling Tobj_ServantBase::_add_ref with a parameter identifying the servant.
Note: In applications written using BEA Tuxedo release 8.0 or later, use the Tobj_ServantBase::_add_ref method instead of the TP::application_responsibility() method. Unlike the TP::application_responsibility() method, the add_ref() method takes no arguments.
The advantage of the application taking responsibility for the servant is that the servant does not have to be created anew. If obtaining the servant is an expensive proposition, the application may choose to save the servant and reuse it later. This is especially likely to be true for servants for preactivated objects, but is true in general. For example, the next time the TP Framework makes a call on Server::create_servant or ServerBase::create_servant_with_id, the application might return a previously saved servant.
Additionally, once an application has taken responsibility for a servant, the application must take care to remove the servant (using Tobj_ServantBase::_remove_ref) when the servant is no longer needed, that is, when the reference count drops to zero, the same as for any other C++ instance. For more information about how the _remove_ref() method works, see Tobj_ServantBase::_remove_ref().
For more information on writing single-threaded and multithreaded server applications, see Creating CORBA Server Applications.
Saving and Restoring Object State
While CORBA objects are active, their state is contained in a servant. Unless an application uses TP::create_active_object_reference, state must be initialized when the object is first invoked (that is, the first time a method is invoked on a CORBA object after its object reference is created), and on subsequent invocations after they have been deactivated. While a CORBA object is deactivated, its state must be saved outside the process in which the servant was active. The object's state can be saved in shared memory, in a file, or in a database. Before a CORBA object is deactivated, its state must be saved, and when it is activated, its state must be restored.
The programmer determines what constitutes an object's state and what must be saved before an object is deactivated, and restored when an object is activated.
Note On Use of Constructors and Destructors for CORBA Objects
The state of CORBA objects must not be initialized, saved, or restored in the constructors or destructors for the servant classes. This is because the TP Framework may reuse an instance of a servant rather than deleting it at deactivation. No guarantee is made as to the timing of the creation and deletion of servant instances.
Transactions
The following sections provide information about transaction policies and how to use transactions.
Transaction Policies
Eligibility of CORBA objects to participate in global transactions is controlled by the transaction policies assigned to implementations at compile time. The following policies can be assigned.
Note: The transaction policies are set in an ICF file that is configured at OMG IDL compile time. For a description of the ICF file, refer to the Implementation Configuration File (ICF) section.
The implementation is not transactional. Objects created for this interface can never be involved in a transaction. The system generates an exception (INVALID_TRANSACTION) if an implementation with this policy is involved in a transaction. An AUTOTRAN policy specified in the UBBCONFIG file for the interface is ignored.
The implementation is not transactional. This policy instructs the system to allow requests within a transaction to be made of this implementation. An AUTOTRAN policy specified in the UBBCONFIG file for the interface is ignored.
The implementation may be transactional. Objects can be involved in a transaction if the request is transactional. Servers containing transactional objects must be configured within a group associated with an XA-compliant resource manager. If the AUTOTRAN parameter is specified in the UBBCONFIG file for the interface, AUTOTRAN is on.
The implementation is transactional. Objects are required to always be involved in a transaction. If a request is made outside a transaction, the system automatically starts a transaction before invoking the method. The transaction is committed when the method ends. (This is the same behavior that results from specifying AUTOTRAN for an object with the option transaction policy, except that no administrative configuration is necessary to achieve this behavior, and it cannot be overridden by administrative configuration.) Servers containing transactional objects must be configured within a group that is associated with an XA-compliant resource manager.
Note: The optional policy is the only transaction policy that can be influenced by administrative configuration. If the system administrator sets the AUTOTRAN attribute for the interface by means of the UBBCONFIG file or by using administrative tools, the system automatically starts a transaction upon invocation of the object, if it is not already infected with a transaction (that is, the behavior is as if the always policy were specified).
Transaction Initiation
Transactions are initiated in one of two ways:
For more information, see Using CORBA Transactions.
Transaction Termination
In general, the handling of the outcome of a transaction is the responsibility of the initiator. Therefore, the following are true:
The following behavior is enforced by the BEA Tuxedo system:
Transaction Suspend and Resume
The CORBA object must follow strict rules with respect to suspending and resuming a transaction within a method invocation. These rules and the error conditions that result from their violation are described below.
When a CORBA object method begins execution, it can be in one of the following three states with respect to transactions:
Note: For each CORBA interface, set AUTOTRAN to Yes if you want a transaction to start automatically when an operation invocation is received. Setting AUTOTRAN to Yes has no effect if the interface is already in transaction mode. For more information about AUTOTRAN, see Using CORBA Transactions.
Note: Not recommended. The transaction may be timed out and aborted before the method causes the transaction to be resumed.
t Begin and commit a transaction within the method execution.
t Begin and roll back a transaction within the method execution.
t Begin and suspend a transaction within the method execution.
Restrictions on Transactions
The following restrictions apply to BEA Tuxedo CORBA transactions:
SQL and Global Transactions
Adhere to the following guidelines when using SQL and Global Transactions:
Note: This is not an issue when an application uses the XA library to connect to the Oracle server because those applications can operate only on global transactions. The Oracle server does not allow local transactions when it is using XA.
Voting on Transaction Outcome
CORBA objects can affect transaction outcome during two stages of transaction processing:
The Current.rollback_only method can be used to ensure that the only possible outcome is to roll back the current transaction. Current.rollback_only() can be invoked from any CORBA object method.
CORBA objects that have the transaction activation policy are given a chance to vote whether the transaction should commit or roll back after transactional work is completed. These objects are notified of the completion of transactional work prior to the start of the two-phase commit algorithm when the TP Framework invokes their deactivate_object method.
Note that this behavior does not apply to objects with process or method activation policies. If the CORBA object wants to roll back the transaction, it can call Current::rollback_only. If it wants to vote to commit the transaction, it does not make that call. Note, however, that a vote to commit does not guarantee that the transaction is committed, since other objects may subsequently vote to roll back the transaction.
Note: Users of SQL cursors must be careful when using an object with the method or process activation policy. A process opens an SQL cursor within a client-initiated transaction. For typical SQL database products, once the client commits the transaction, all cursors that were opened within that transaction are automatically closed; however, the object will not receive any notification that its cursor has been closed.
Transaction Timeouts
When a transaction timeout occurs, the transaction is marked so that the only possible outcome is to roll back the transaction, and the CORBA::TRANSACTION_ROLLEDBACK standard exception is returned to the client. Any attempts to send new requests will also fail with the CORBA::TRANSACTION_ROLLEDBACK exception until the transaction has been aborted.
Parallel Objects
Support for parallel objects was added to BEA Tuxedo CORBA in release 8.0 as a performance enhancement. The parallel objects feature enables you to designate all business objects in a particular application as stateless objects. The effect is that, unlike stateful business objects, which can only run on one server in a single domain, stateless business objects can run on all servers in a single domain. Thus, the benefits of parallel objects are as follows:
For more information on parallel objects, see Scaling, Distributing, and Tuning CORBA Applications.
To implement parallel objects, the concurrency policy option has been added to the ICF file. To select parallel objects for a particular application, you set the concurrency policy option to user-controlled. When you select user-controlled concurrency, the business object are not registered with the Active Object Map (AOM) and, therefore, are stateless and can be active on more than one server at a time. Thus, these objects are referred to as parallel objects.
If user-controlled concurrency is selected, the servant implementation must comply with one of the following statements:
In release 8.0 of the BEA Tuxedo software, the Implementation Configuration File (ICF) was modified to support user-controlled concurrency. In Listing 3-1, the changes to add this support are highlighted in bold type. For a description of the ICF syntax, see ICF Syntax.
Listing 3-1 ICF Syntax
[#pragma activation_policy method|transaction|process]
[#pragma transaction_policy never|ignore|optional|always]
[#pragma concurrency_policy user_controlled|system_controlled]
[Module module-name {]
implementation [implementation-name]
{
implements (module-name::interface-name);
[activation_policy (method|transaction|process);]
[transaction_policy (never|ignore|optional|always);]
[concurrency_policy (user_controlled|system_controlled);]
};
[};]
User-controlled concurrency can be used with factory-based routing, all activation policies, and all transaction policies. The interaction with these features is as follows:
If the user specifies factory-based routing when creating the object, then the object will route to a server in that group. The object key contains the group selected during factory-based routing, but the client routing code will recognize that the interface has user-controlled concurrency and specify the desired group. This is accomplished using normal BEA Tuxedo routing.
The TP Framework handles active user-controlled concurrency objects in the same manner as system-controlled concurrency objects. The TP Framework stores information about objects in the local AOM, and calls the activate_object and deactivate_object methods at the appropriate times. However, the object will not have an entry in the AOM and the TP Framework will not call any AOM routines. For example, on shutdown, since an active object will not have an AOM handle, calls to remove the entry from the AOM will not be invoked.
The TP Framework handles active user-controlled concurrency objects in the same manner as system-controlled concurrency objects. The TP Framework is called back for transaction events and the TP Framework stores information about transactional user-controlled objects in the local AOM. The main differences when using parallel objects in transactions as opposed to stateful objects are that the AOM is not used for GTRID information and the AOM routines are not called to update or retrieve transactional information.
Note: There is one restriction with user-controlled concurrency. TP::create_active_object_reference throws a TobjS::IllegalOperation exception if it is passed an interface with user-controlled concurrency set. Since the AOM is not used when user-controlled concurrency is set, there is no way for the TP Framework to connect an active object to this server.
TP Framework API
This section describes the TP Framework API. Additional information about how to use this API can be found in Creating CORBA Server Applications.
The TP Framework comprises the following components:
The visible part of the TP Framework consists of two categories of operations:
Server Interface
The Server interface provides callback methods that can be used for application-specific server initialization and termination logic. This interface also provides a callback method that is used to create servants when servants are required for object activation.
The Server interface has the following characteristics:
For a description of the Server interface methods, see ServerBase Interface.
C++ Declarations
For the C++ mappings, seeServerBase Interface.
ServerBase Interface
The serverBase interface allows you to take full advantage of multithreading capabilities. You can create your own Server classes that inherit from the ServerBase class. This provides you with the following:
The ServerBase class provides the same operations that were available in the Server class in earlier releases. The Server class inherits from the ServerBase class.
These methods can be used with single-threaded and multithreaded applications:
These methods can be used with multithreaded server applications only:
Note: Programmers must provide definitions of the Server class methods. The ServerBase class methods have default implementations.
C++ Declarations (in Server.h)
The C++ mapping is as follows:
class OBBEXPDLLUSER ServerBase {
public:
virtual CORBA::Boolean
initialize(int argc, char** argv) = 0;
virtual void
release() = 0;
virtual Tobj_Servant
create_servant(const char* interfaceName) = 0;
// Default Implementations Supplied
virtual Tobj_Servant
create_servant_with_id(const char* interfaceName,
const char* stroid);
virtual CORBA::Boolean
thread_initialize(int argc, char** argv);
virtual void
thread_release();
};
class Server : public ServerBase {
public:
CORBA::Boolean initialize(int argc, char** argv);
void release();
Tobj_Servant create_servant(const char* interfaceName);
};
Server::create_servant()
Synopsis
Creates a servant to instantiate a C++ object.
C++ Binding
class Server {
public:
Tobj_Servant create_servant(const char* interfaceName);
};
Argument
Exception
If an exception is thrown in Server::create_servant(), the TP Framework catches the exception. Activation fails. A CORBA::OBJECT_NOT_EXIST() exception is raised back to the client. In addition, an error message is written to the user log (ULOG) file, as follows, for each exception type:
Description
The create_servant method is invoked by the TP Framework when a request arrives at the server and there is no available servant to satisfy the request. The TP Framework calls the create_servant method with the interface name for the servant to be created. The server application instantiates an appropriate C++ object and returns a pointer to it. Typically, the method contains a switch statement on the interface name and creates a new object, depending on the interface name.
Caution: The server application must not depend on this method being invoked for every activation of a CORBA object. The server application must not do any handling of CORBA object state in the constructors or destructors of any servant classes for CORBA objects. This is because the TP Framework may possibly reuse servants on activation and may possibly not destroy servants on deactivation.
Return Value
Note: The restriction on the length of the ObjectId has been removed in this release.
ServerBase::create_servant_with_id()
Synopsis
Creates a servant for this target object. This method supports the development of single-headed and multithreaded server applications.
C++ Binding
Tobj_Servant create_servant_with_id (const char* interfaceName,
const char* stroid);
Arguments
Description
The TP Framework invokes the create_servant_with_id method when a request arrives at the server and there no servant is available to satisfy the request. The TP Framework passes in the interface name for the servant to be created and the object ID associated with the object with which the servant will be associated. The server application instantiates an appropriate C++ object and returns a pointer to it. Typically, the method contains a switch statement on the interface name and creates a new object, depending on the interface name. Providing the object ID allows a servant implementation to make decisions during the creation of the servant instance that require knowledge of the target object. Reentrancy support is one example of how a servant implementation might employ knowledge of the target object.
The ServerBase class provides a default implementation of create_servant_with_id which calls the standard create_servant method passing the interface name. This default implementation ignores the target object ID parameter.
Caution: The server application must not depend on the invocation of this method for every activation of a CORBA object. The server application must not handle the CORBA object state in the constructors or destructors of any servant classes for CORBA objects. This is because the TP Framework might reuse servants on activation and might not destroy servants on deactivation.
Return Value
Example
Tobj_Servant simple_per_request_server::create_servant_with_id(
const char* intf_repos_id, const char* stroid)
{
TP::userlog("create_servant_with_id called in thread %ld",
(unsigned long)SIMPTHR_GETCURRENTTHREADID);
// Perform any necessary initialization based on
// this object ID
return create_servant(intf_repos_id);
}
Server::initialize()
Synopsis
Allows the application to perform application-specific initialization procedures, such as logging into a database, creating and registering well-known object factories, initializing global variables, and so forth.
C++ Binding
class Server {
public:
CORBA::Boolean initialize(int argc, char** argv);
};
Arguments
The argc and argv arguments are passed from the command line. The argc argument contains the name of the server. The argv argument contains the first command-line option that is specific to the application, if there are any.
Command-line options are specified in the UBBCONFIG file using the CLOPT parameter in the entry for the server in the SERVERS section. System-recognized options come first in the CLOPT parameter, followed by a double-hyphen (--), followed by the application-specific options. The value of argc is one greater than the number of application-specific options. For details, see ubbconfig(5) in the File Formats, Data Descriptions, MIBs, and System Processes Reference.
Exceptions
If an exception is raised in Server::initialize(), the TP Framework catches the exception. The TP Framework behavior is the same as if initialize() returned FALSE (that is, an exception is considered to be a failure). In addition, an error message is written to the user log (ULOG) file, as follows, for each exception type:
"Couldn't register factory");
Description
The initialize callback method, which is invoked as the last step in server initialization, allows the application to perform application-specific initialization.
Typically, a server application does the following tasks in Server::initialize:
It is the responsibility of the server application to open any required XA resource managers. This is done by invoking either of the following methods:
Note: You must use the TP::open_xa_rm() method if you use the INS bootstrap mechanism to obtain initial object references.
Return Value
Boolean TRUE or FALSE. TRUE indicates success. FALSE indicates failure. If an error occurs in initialize(), the application code should return FALSE. The application code should not call the system call exit(). Calling exit() does not give the TP Framework a chance to release resources allocated during startup and may cause unpredictable results.
If the return value is FALSE:
ServerBase::thread_initialize()
Synopsis
Performs any necessary application-specific initialization for a thread created using the BEA Tuxedo software. This method supports the development of a multithreaded server application.
C++ Binding
CORBA::Boolean thread_initialize(int argc, char** argv)
Arguments
Description
In managing the thread pool, the BEA Tuxedo software creates and releases threads using the operating system thread library services. Depending on application requirements, these threads might need to be initialized before they are used to process requests.
The thread_initialize callback method is invoked each time a thread is created, to initialize the thread. Note that the BEA Tuxedo software manages a number of system-owned threads that are used for dispatching requests; these system-owned threads are in addition to those threads in the thread pool. Under some circumstances the servant methods you implement are also executed in these system-owned threads; for this reason the BEA Tuxedo software invokes the thread_initialize method to initialize the system-owned threads.
The ServerBase class provides a default implementation of the thread_initialize method that opens the XA resource manager in the initialized thread.
Return Value
Example
CORBA::Boolean simple_per_request_server::thread_initialize(
int argc, char** argv)
{
TP::userlog("thread_initialize called in thread %ld",
(unsigned long)SIMPTHR_GETCURRENTTHREADID);
return CORBA_TRUE;
}
Server::release()
Synopsis
Allows the application to perform any application-specific cleanup, such as logging off a database, unregistering well-known factories, or deallocating resources.
C++ Binding
typedef Tobj_ServantBase* Tobj_Servant;
class Server {
public:
void release();
};
Arguments
None.
Exceptions
If an exception is raised in release(), the TP Framework catches the exception. Each exception causes an error message to be written to the user log (ULOG) file, as follows:
"Couldn't unregister factory");
In all cases, the server continues to exit.
Description
The release callback method, which is invoked as the first step in server shutdown, allows the server application to perform any application-specific cleanup. The user must override the virtual function definition.
Typical tasks performed by the application in this method are as follows:
This method is normally called in response to a tmshutdown command from the administrator or operator.
The TP Framework provides a default implementation of Server::release(). The default implementation closes XA resource managers for the server. The implementation does this by issuing a tx_close() invocation, which uses the default CLOSEINFO configured for the server's group in the UBBCONFIG file.
It is the responsibility of the application to close any open XA resource managers. This is done by issuing either of the following calls:
Note: You must use the TP::close_xa_rm() method if you use the INS bootstrap mechanism to obtain initial object references.
Note: Once a server receives a request from the tmshutdown(1) command to shut down, it can no longer receive requests from other remote objects. This may require servers to be shut down in a specific order. For example, if the Server::release() method in Server 1 needs to access a method of an object that resides in Server 2, Server 2 should be shut down after Sever 1 is shut down. In particular, the TP::unregister_factory() method accesses the FactoryFinder Registrar object that resides in a separate server. The TP::unregister_factory() method is typically invoked from the release() method; therefore, the FactoryFinder server should be shut down after all servers that call TP::unregister_factory() in their Server::release() method.
Return Value
None.
ServerBase::thread_release()
Synopsis
Performs application-specific cleanup when a thread that was created by the BEA Tuxedo software is released. This method supports the development of a multithreaded server application.
C++ Binding
void thread_release()
Arguments
None.
Description
The thread_release callback method is invoked each time a thread is released. Implement the thread_release method as necessary to perform application-specific resource cleanup.
The ServerBase class provides a default implementation of the thread_release method that closes the XA resource manager in the released thread.
Return Value
None.
Example
void simple_per_request_server::thread_release()
{
TP::userlog("thread_release called in thread %ld",
(unsigned long)SIMPTHR_GETCURRENTTHREADID);
}
Tobj_ServantBase Interface
The Tobj_ServantBase interface inherits from the PortableServer::RefCountServantBase class and defines operations that allow a CORBA object to assist in the management of its state in a thread-safe manner. Every implementation skeleton generated by the IDL compiler automatically inherits from the Tobj_ServantBase class. The Tobj_ServantBase class contains two virtual methods, activate_object() and deactivate_object(), that may be optionally implemented by the programmer.
Whenever a request comes in for an inactive CORBA object, the object is activated and the activate_object() method is invoked on the servant. When the CORBA object is deactivated, the deactivate_object() method is invoked on the servant. The timing of deactivation is driven by the implementation's activation policy. When the deactivate_object() method is invoked, the TP Framework passes in a reason code to indicate why the call was made.
These methods support the development of a multithreaded server application:
Note: Tobj_ServantBase::activate_object() and Tobj_ServantBase::deactivate_object() are the only methods that the TP Framework guarantees will be invoked for CORBA object activation and deactivation. The servant class constructor and destructor may or may not be invoked at activation or deactivation time (through the Server::create_servant call for C++). Therefore, the server application code must not do any state handling for CORBA objects in either the constructor or destructor of the servant class.
Note: The programmer does not need to use a cast or reference to Tobj_ServantBase directly. The Tobj_ServantBase methods show up as part of the skeleton and, therefore, in the implementation class for a servant. The programmer may provide definitions for the activate_object and deactivate_object methods, but the programmer should never make direct invocations on those methods; only the TP Framework should call those methods.
C++ Declaration (in Tobj_ServantBase.h)
The C++ mapping for the Tobj_servantBase interface is as follows:
class Tobj_ServantBase : public PortableServer::RefCountServantBase {
public:
Tobj_ServantBase& operator=(const Tobj_ServantBase&);
Tobj_ServantBase() {}
Tobj_ServantBase(const Tobj_ServantBase& s) :
PortableServer::RefCountServantBase(s) {}
virtual void activate_object(const char *) {}
virtual void deactivate_object(const char*,
TobjS::DeactivateReasonValue) {}
virtual CORBA::Boolean _is_reentrant() { return CORBA_FALSE; }
};
typedef Tobj_ServantBase * Tobj_Servant;
Tobj_ServantBase:: activate_object()
Synopsis
Associates an object ID with a servant. This method gives the application an opportunity to restore the object's state when the object is activated. The state may be restored from shared memory, from an ordinary flat file, or from a database file.
C++ Binding
class Tobj_ServantBase : public PortableServer::ServantBase {
public:
virtual void activate_object(const char * stroid) {}
};
Argument
Note: The restriction on the length of the object ID has been removed in this release.
Description
Object activation is triggered by a client invoking a method on an inactive CORBA object. This causes the Portable Object Adapter (POA) to assign a servant to the CORBA object. The activate_object() method is invoked before the method invoked by the client is invoked. If activate_object() returns successfully, that is, without raising an exception, the requested method is executed on the servant.
The activate_object() and deactivate_object() methods and the method invoked by the client can be used by the programmer to manage object state. The particular way these methods are used to manage object state may vary according to the needs of the application. For a discussion of how these methods might be used, see Creating CORBA Server Applications.
If the object is currently infected with a global transaction, activate_object() executes within the scope of that same global transaction.
It is the responsibility of the programmer of the object to check that the stored state of the object is consistent. In other words, it is up to the application code to save a persistent flag that indicates whether or not deactivate_object() successfully saved the state of the object. That flag should be checked in activate_object().
Return Value
None.
Exceptions
If an error occurs while executing activate_object(), the application code should raise either a CORBA standard exception or a TobjS::ActivateObjectFailed exception. When an exception is raised, the TP Framework catches the exception, and the following events occur:
Note: For each CORBA interface, set AUTOTRAN to Yes if you want a transaction to start automatically when an operation invocation is received. Setting AUTOTRAN to Yes has no effect if the interface is already in transaction mode. For more information about AUTOTRAN, see Using CORBA Transactions.
Tobj_ServantBase::_add_ref()
Synopsis
Adds a reference to a servant. This method supports the development of a multithreaded server application.
Note: In applications written using BEA Tuxedo release 8.0 or later, use this method instead of the TP::application_responsibility() method.
C++ Binding
void _add_ref()
Arguments
None.
Description
Invoke this method when a reference to a servant is needed. Invoking this method causes the reference count for the servant to increment by one.
Return Value
None.
Example
myServant * servant = new intf_i();
if(servant != NULL)
servant->_add_ref();
Tobj_ServantBase::deactivate_object()
Synopsis
Removes the association of an object ID with its servant. This method gives the application an opportunity to save all or part of the object's state before the object is deactivated. The state may be saved in shared memory, in an ordinary flat file, or in a database file.
C++ Binding
class Tobj_ServantBase : public PortableServer::ServantBase {
public:
virtual void deactivate_object(const char* stroid,
TobjS::DeactivateReasonValue reason) {}
};
Arguments
Note: The restriction on the length of the object ID has been removed in this release.