Creating CORBA Server Applications

     Previous  Next    Open TOC in new window  Open Index in new window  View as PDF - New Window  Get Adobe Reader - New Window
Content starts here

Wrapping a BEA Tuxedo Service in a CORBA Object

This chapter presents an overview of one way in which you can call a BEA 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:

The Wrapper sample application delegates a set of billing operations to a BEA 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 a BEA Tuxedo application into a BEA 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 BEA Tuxedo services are wrapped as operations on a CORBA object; thus, the object delegates its work to the BEA Tuxedo application. If you have a set of BEA 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 BEA Tuxedo ATMI applications. For information about how to build and configure BEA Tuxedo ATMI applications, and for information about how they work, see the BEA Tuxedo ATMI information set, which is included in the BEA Tuxedo online documentation.

 


Overview of Wrapping a BEA Tuxedo Service

The process described in this chapter for wrapping a set of BEA Tuxedo services encompasses the following steps:

  1. Designing the object that structures a set of tasks that are oriented to the BEA Tuxedo system as operations on that object.
  2. Creating the message buffer used by the BEA Tuxedo services. You use this message buffer to send and receive messages to and from the BEA Tuxedo services. You can allocate the buffer in the object's constructor in the application's implementation file.
  3. Implementing on the object the operations that send and receive messages to and from the BEA Tuxedo services. This step also includes choosing the implementation for how the BEA Tuxedo services are called.

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 BEA Tuxedo ATMI application that implements the services called from the CORBA object.

Designing the Object That Wraps the BEA Tuxedo Service

The first step described in this chapter is designing the object that wraps the calls to the BEA 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 BEA Tuxedo ATMI teller application.

The BEA Tuxedo ATMI teller application used by the Wrapper sample application contains the following services:

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 BEA 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 BEA Tuxedo ATMI teller application's CURRBALANCE service.
  4. The BEA Tuxedo ATMI teller application receives the message buffer, extracts its contents, and makes the appropriate call to the CURRBALANCE service.
  5. The CURRBALANCE service obtains from the University database the current balance of the account and gives it to the BEA Tuxedo ATMI teller application.
  6. The BEA Tuxedo ATMI teller application inserts the current balance into a message buffer and returns it to the Teller object.
  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 BEA Tuxedo Service Calls

The next step described in this chapter is creating the buffer within which messages are sent between the object and the BEA Tuxedo service. There are a number of buffer types that may be used by various BEA 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 BEA Tuxedo system, see the BEA 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 BEA 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 BEA 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:

Code
Description
tpalloc
Allocates the buffer.
"FML32"
Specifies the FML buffer type.
""
Typically enclose any flags passed to the BEA Tuxedo service. In this example, no flags are passed.
1000
Specifies the buffer size in bytes.

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 BEA Tuxedo Service

The next step is implementing the operations on the object that wraps calls to the BEA Tuxedo ATMI application. In this step, you choose the implementation of how the BEA Tuxedo services are called from the object. The Wrapper sample application uses the tpcall implementation.

An operation on an object that wraps a BEA Tuxedo service typically includes statements that do the following:

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 BEA 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 BEA Tuxedo ATMI FML Function Reference.

Fchg32(m_tuxbuf, ACCOUNT_NO, 0, (char*)&account, 0);

The following statement calls the CURRBALANCE BEA Tuxedo service, via the tpcall implementation, passing the message buffer. This statement also specifies where the BEA 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 BEA 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 BEA Tuxedo services within a BEA Tuxedo domain:

 


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:

In addition, the UBBCONFIG file for the Wrapper sample application specifies the following groups:

The configuration of the BEA Tuxedo domain in the Wrapper sample application is shown in the following figure.

Incorporating a BEA Tuxedo ATMI application into the University sample applications makes sense from the standpoint of using the Process-Entity design pattern. BEA 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 BEA 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:
    • The student's account number from the student table in the database
    • The student's balance from the account table in the database, which is obtained by invoking the get_balance() operation on the Teller object
  2. The student browses courses, as with the Basic sample application, and identifies a list of courses for which he or she wants to register.
  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 BEA 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 BEA 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.
  7. 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).

  8. 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:

Additional Design Considerations for the Wrapper Sample Application

The following additional considerations influence the design of the Wrapper sample application:

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:

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, BEA 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:

For information about building, configuring, and running the Wrapper sample application, see the Guide to the CORBA University Sample Applications.


  Back to Top       Previous  Next