Table of Contents Previous Next PDF


Wrapping an Oracle Tuxedo Service in a CORBA Object

Wrapping an Oracle Tuxedo Service in a CORBA Object
This chapter presents an overview of one way in which you can call an Oracle Tuxedo service from within an object managed by a CORBA server application, using the Wrapper sample application as an example.
This topic includes the following sections:
This section describes:
The Wrapper sample application delegates a set of billing operations to an Oracle Tuxedo ATMI teller application, which contains a set of services that perform basic billing procedures. The approach in this chapter shows one technique for incorporating an Oracle Tuxedo application into an Oracle Tuxedo domain.
The examples shown in this chapter demonstrate a one-to-one relationship between operations on a CORBA object and calls to specific services within an application. In a sense, the calls to the Oracle Tuxedo services are wrapped as operations on a CORBA object; thus, the object delegates its work to the Oracle Tuxedo application. If you have a set of Oracle Tuxedo services that you want to use in a CORBA server application, the technique shown in this chapter may work for you.
This chapter does not provide any details about Oracle Tuxedo ATMI applications. For information about how to build and configure Oracle Tuxedo ATMI applications, and for information about how they work, see the Oracle Tuxedo ATMI information set, which is included in the Oracle Tuxedo online documentation.
Overview of Wrapping an Oracle Tuxedo Service
The process described in this chapter for wrapping a set of Oracle Tuxedo services encompasses the following steps:
1.
2.
3.
The following figure shows a high-level view of the relationship among the client application, the CORBA object managed by the CORBA server application, and the Oracle Tuxedo ATMI application that implements the services called from the CORBA object.
Designing the Object That Wraps the Oracle Tuxedo Service
The first step described in this chapter is designing the object that wraps the calls to the Oracle Tuxedo ATMI application. For example, the goal for the Wrapper sample application is to add billing capability to the student registration process, which can be done by delegating a set of billing operations to an existing Oracle Tuxedo ATMI teller application.
The Oracle Tuxedo ATMI teller application used by the Wrapper sample application contains the following services:
CURRBALANCE—obtains the current balance of a given account
CREDIT—credits an account by a given dollar amount
DEBIT—debits an account by a given dollar amount
To wrap these services, the Wrapper sample application includes a separate OMG IDL file that defines a new interface, Teller, which has the following operations:
Each of these operations on the Teller object maps one-to-one to calls on the services in the Oracle Tuxedo ATMI teller application.
A typical usage scenario of the Teller object may be the following:
1.
The client application invokes the register_for_courses() operation on the Registrar object, which requires a student ID.
2.
As part of the registration process, the Registrar object invokes the get_balance() operation on the Teller object, passing an account number.
3.
The get_balance() operation on the Teller object puts the account number into a message buffer and sends the buffer to the Oracle Tuxedo ATMI teller application’s CURRBALANCE service.
4.
5.
The CURRBALANCE service obtains from the University database the current balance of the account and gives it to the Oracle Tuxedo ATMI teller application.
6.
7.
The Teller object extracts the current balance amount from the message buffer and returns the current balance to the Registrar object.
For more design information about the Teller object and the Wrapper sample application, see the section “Design Considerations for the Wrapper Sample Application” on page -7.
Creating the Buffer in Which to Encapsulate Oracle Tuxedo Service Calls
The next step described in this chapter is creating the buffer within which messages are sent between the object and the Oracle Tuxedo service. There are a number of buffer types that may be used by various Oracle Tuxedo ATMI applications, and the examples used in this chapter are based on the FML buffer type. For more information about buffer types in the Oracle Tuxedo system, see the Oracle Tuxedo information set.
In your application implementation file, you need to allocate the chosen buffer type. You can allocate the buffer in the object’s constructor, because the buffer you allocate does not need to be unique to any particular Teller object instance. This allocation operation typically includes specifying the buffer type, passing any flags appropriate for the procedure call to the Oracle Tuxedo service, and specifying a buffer size.
You also need to add to your implementation’s header file the definition of the variable that represents the buffer.
The following code example shows the constructor for the Wrapper application’s Teller object that allocates the Oracle Tuxedo buffer, m_tuxbuf:
Teller_i::Teller_i() :
m_tuxbuf((FBFR32*)tpalloc("FML32", "", 1000))
{
if (m_tuxbuf == 0) {
throw CORBA::INTERNAL();
}
}
Note the following about the line that allocates the FML buffer:
 
The object’s implementation file should also deallocate the buffer in the destructor, as in the following statement from the Wrapper application implementation file:
tpfree((char*)m_tuxbuf);
Implementing the Operations That Send Messages to and from the Oracle Tuxedo Service
The next step is implementing the operations on the object that wraps calls to the Oracle Tuxedo ATMI application. In this step, you choose the implementation of how the Oracle Tuxedo services are called from the object. The Wrapper sample application uses the tpcall implementation.
An operation on an object that wraps an Oracle Tuxedo service typically includes statements that do the following:
a.
b.
c.
d.
The following example shows the implementation of the get_balance() operation in the Wrapper application Teller object. This operation retrieves the balance of a specific account, and the Oracle Tuxedo service being called is CURRBALANCE.
CORBA::Double Teller_i::get_balance(BillingW::AccountNumber account)
{
// "marshal" the "in" parameters (account number)
Fchg32(m_tuxbuf, ACCOUNT_NO, 0, (char*)&account, 0);
long size = Fsizeof32(tuxbuf);
// Call the CURRBALANCE Tuxedo service
if (tpcall("CURRBALANCE", (char*)tuxbuf, 0,
(char**)&tuxbuf, &size, 0) ) {
throw CORBA::PERSIST_STORE();
}
// "unmarshal" the "out" parameters (current balance)
CORBA::Double currbal;
Fget32(m_tuxbuf, CURR_BALANCE, 0, (char*)&currbal, 0);
return currbal;
}
The statement in the following code example fills the message buffer, m_tuxbuf, with the student account number. For information about FML, see the Oracle Tuxedo ATMI FML Function Reference.
Fchg32(m_tuxbuf, ACCOUNT_NO, 0, (char*)&account, 0);
The following statement calls the CURRBALANCE Oracle Tuxedo service, via the tpcall implementation, passing the message buffer. This statement also specifies where the Oracle Tuxedo service response is to be placed, which in this example is also the same buffer as the one in which the request was sent.
if (tpcall("CURRBALANCE", (char*)tuxbuf, 0,
(char**)&tuxbuf, &size, 0) ) {
throw CORBA::PERSIST_STORE();
}
The following statement extracts the balance from the returned Oracle Tuxedo message buffer:
Fget32(m_tuxbuf, CURR_BALANCE, 0, (char*)&currbal, 0);
The last line in the get_balance() operation returns the results to the client application:
return currbal;
Restrictions
Note the following restrictions regarding how you can incorporate Oracle Tuxedo services within an Oracle Tuxedo domain:
You may not include the tpreturn() or tpforward() Oracle Tuxedo implementations within an object that calls an Oracle Tuxedo service.
Design Considerations for the Wrapper Sample Application
The basic design considerations for the Wrapper sample application are based on the scenario that is described in this section. When a student registers for a course, the Registrar object performs, as part of its registration process, invocations to the Teller object, which charges the student’s account for the course.
This section describes the design for the Wrapper sample application, which incorporates an additional server application, Billing, into the configuration. Therefore, the Wrapper sample application consists of the following four server applications:
University, which has the RegistrarFactory, Registrar, and CourseSynopsisEnumerator objects
Billing, which has the TellerFactory and Teller objects
Oracle Tuxedo ATMI Teller Application, which has the CURRBALANCE, CREDIT, and DEBIT services
In addition, the UBBCONFIG file for the Wrapper sample application specifies the following groups:
The configuration of the Oracle Tuxedo domain in the Wrapper sample application is shown in the following figure.
Incorporating an Oracle Tuxedo ATMI application into the University sample applications makes sense from the standpoint of using the Process-Entity design pattern. Oracle Tuxedo ATMI applications generally implement the Process-Entity design pattern, which are also used in the University sample applications.
The University database is updated to include a new table containing account information for each student. Therefore, when services in the Oracle Tuxedo ATMI Teller Application process billing data, they perform transactions using the University database.
How the Wrapper University Sample Application Works
A typical usage scenario in the Wrapper sample application encompasses the following sequence of events:
1.
After the student logon procedure, the client application invokes the get_student_details() operation on the Registrar object. Included in the implementation of the get_student_details() operation is code that retrieves:
2.
3.
The client application sends a request to the Registrar object, as with the Transactions sample application scenario, to invoke the register_for_courses() operation. The request continues to include only a list of course numbers and a student ID.
4.
While registering the student for the list of courses, the register_for_courses() operation invokes:
The get_balance() operation on the Teller object, to make sure that the student does not have a delinquent account
The debit() operation on the Teller object, which is managed by the Billing server application to bill for courses
5.
The get_balance() and debit() operations on the Teller object each send a request to the Oracle Tuxedo ATMI Teller application. Encapsulated in the request is an FML buffer containing the appropriate calls, including the account number calls to, respectively, the CURRBALANCE and DEBIT services in the Oracle Tuxedo ATMI Teller application.
6.
The CURRBALANCE and DEBIT services perform the appropriate database calls to, respectively, obtain the current balance and debit the student’s account to reflect the charges for the courses for which he or she has registered.
If the student has a delinquent account, the Registrar object returns the DelinquentAccount exception to the client application. The client application then rolls back the transaction.
If the debit() operation fails, the Teller object invokes the rollback_only() operation on the TransactionCurrent object. Because the Teller and Registrar objects are scoped within the same transaction, this rollback affects the entire registration process and thus prevents the situation where there is an inconsistent database (showing, for example, that the student is registered for the course, but the student’s account balance has not been debited for the course).
7.
If no exceptions have been raised, the Registrar object registers the student for the desired courses.
Interface Definitions for the Billing Server Application
The following interface definitions are defined for the Billing server application:
The TellerFactory object, whose only operation is find_teller(). The find_teller() operation works exactly the same as the find_registrar() operation in the University server RegistrarFactory object.
The Teller object, which, as mentioned earlier, implements the following operations:
Like the Registrar object, the Teller object has no state data and does not have a unique object ID (OID).
Additional Design Considerations for the Wrapper Sample Application
The following additional considerations influence the design of the Wrapper sample application:
The Registrar object needs a way to send requests to the Teller object to handle billing operations.
Both of these considerations have implications on the UBBCONFIG file for the Wrapper sample application. The following sections discuss these and other additional design considerations in detail.
Sending Requests to the Teller Object
Up until now, all the objects in the University server application have been defined in the same server process. Therefore, for one object to send a request to another object is fairly straightforward, and is summarized in the following steps, using the Registrar and CourseSynopsisEnumerator objects as an example:
1.
The Registrar object creates an object reference to the CourseSynopsisEnumerator object.
2.
Using the newly created object reference, the Registrar object sends the request to the CourseSynopsisEnumerator object.
3.
If the CourseSynopsisEnumerator object is not in memory, the TP Framework invokes the Server::create_servant() operation on the Server object to instantiate the CourseSynopsisEnumerator object.
However, now that there are two server processes running, and an object in one process needs to send a request to an object managed by the second process, the procedure is not quite so straightforward. For example, the notion of getting an object reference to an object in another server process has important implications. For one, the second server process has to be running when the request is made. Also, the factory for the object in the other server process must be available.
The Wrapper sample application addresses this by incorporating the following configuration and design elements:
The University server application gets the object reference to the TellerFactory object in the University Server object’s Server::initialize() operation. The University server application then caches the TellerFactory object reference. This introduces a performance optimization because, otherwise, the Registrar object would need to do the following each time it needs a TellerFactory object:
Invoke the resolve_initial_references() operation on the Bootstrap object to get the FactoryFinder object.
Invoke the find_one_factory_by_id() operation on the FactoryFinder object to obtain a reference to a TellerFactory object.
The Billing server process is started before the University server process is started. When the Registrar object subsequently invokes the TellerFactory object, the Registrar object uses the object reference acquired by the Server::initialize() operation (described in the preceding list item). You specify in the UBBCONFIG file the order in which server processes are started.
To handle billing during the course registration process, the register_for_courses() and get_student_details() operations on the Registrar object are modified to include code that invokes operations on the Teller object.
Exception Handling
The Wrapper sample application is designed to handle the situation in which the amount owed by the student exceeds the maximum allowed. If the student tries to register for a course when he or she owes more than is permitted by University, the Registrar object generates a user-defined DelinquentAccount exception. When this exception is returned to the client application, the client application rolls back the transaction. For information about how to implement user-defined exceptions, see the section “User-defined Exceptions” on page -17.
Setting Transaction Policies on the Interfaces in the Wrapper Sample Application
Another consideration that affects the performance of the Wrapper sample application is setting the appropriate transaction policies for the interfaces of the objects in that application. The Registrar, CourseSynopsisEnumerator, and Teller objects are configured with the always transaction policy. The RegistrarFactory and TellerFactory objects are configured with the ignore transaction policy, which prevents the transactional context from being propagated to these objects, which do not need to be included in transactions.
Configuring the University and Billing Server Applications
As mentioned earlier, the Billing server application is configured in a group separate from the group containing the University database and the University application, Oracle Tuxedo ATMI Teller application, and Oracle Transaction Manager Server (TMS) application.
However, since the Billing server application participates in the transactions that register students for courses, the Billing server application must include invocations to the TP::open_xa_rm() and TP::close_xa_rm() operations in the Server object. This is a requirement for any server application that manages an object that is included in any transaction. If that object does not perform any read or write operations on a database, you can specify the NULL resource manager in the following locations:
In an argument to the buildobjserver command when you build the server application
For information about building, configuring, and running the Wrapper sample application, see the Guide to the CORBA University Sample Applications.
 

Copyright © 1994, 2017, Oracle and/or its affiliates. All rights reserved.