Reliable Transaction Router
C++ Foundation Classes


Previous Contents Index


    % ./server 2 h 

Build and Run the Client: Compile the ABC CLIENT and ABC SHARED modules on the operating system which will run your client application. To build on UNIX:


    % cxx -o client client.c shared.c /usr/shlib/librtr.so -DUNIX 

Run the client with the following command:


    % ./client 1 h 10 

or


    C:\RtrTutor\> client.exe 1 h 10 

In many ways, this tutorial has only scratched the surface of RTR. There is a great deal more that RTR gives you to make your distributed application reliable, available, and perform better. The following sections of this document highlight some of the capabilities you have at your service. For more details on each item, and information on what additional features will help you to enhance your application, look first through the RTR Application Design Guide. Then, earlier sections of this C++ Foundation Classes manual will tell you in detail how to implement each capability.

Compaq Computer Corporation also offers training classes for RTR, and if you'd like to attend any of them, contact your Compaq representative.

Callout Server

RTR supports the concept of a "callout server" for authentication. You may designate an additional application on your server machines or your router machine as a callout server with the RTRFacilityManager class methods. Callout servers will be asked to check all requests in a facility, and are asked to vote on every transaction.

The CreateFacility method in the RTRFacilityManager class includes a boolean parameter bEnableBackendCallout for specifying a callout server.

Events

In addition to messages, RTR can be used to dispatch asynchronous events on servers and clients. A callback function in the user's server and client applications can be designated which RTR will call asynchronously to dispatch events to your application.

Shadowing

This tutorial only discussed failover to a standby server. But RTR also supports shadowing: while your server is making changes to your database, another "shadow" server can be making changes to an exact copy of your database in real time. If your primary server fails, your shadow server will take over, and record all of the transactions occurring while your primary server is down. Your primary server will be given the opportunity to update the original database and catch up to the correct state when it comes back up. Primary and secondary shadow server can also have standby servers for failover! So as you can see, if your database and transactions are important enough to you, you have the opportunity to double and triple protect them with an RTR configuration including any of

Transactions

One of RTR's greatest strengths is in supporting transactions. The RTR Application Design Guide goes into more detail regarding transactions and processing of transactions.

RTR Utility

You've seen how to use the RTR utility (or the command line interface) to start RTR and to create a facility. But the RTR utility contains many more features than this, and in fact can be used to prototype an application. Refer to the RTR System Manager's Manual for details.


Chapter 6
Sample Application Code

The RTR book ordering sample application shows how the C++ Foundation classes can be used to simulate purchasing merchandise for a fictitious company named ABC.

The client, ABCOrderTaker, has a hard-coded book request which is represented by the ABCBook class. This book request has an ISBN number used for data routing. The server will display a dialog box containing the contents of the newly reconstituted ABCBook object.

The following sample application code comes from the Examples directory and includes:

There are also class factory, client and server handlers, ABCMagazine, and ABCCommon classes in the Examples directory.

6.1 Sample Main Program


    #include "ABCCommon.h" 
    #include "ABCOrderTaker.h" 
    #include "ABCOrderProcessor.h" 
    #include "ABCBook.h" 
    #include "ABCMagazine.h" 
    void GenerateOrders(); 
 
    int main(int argc, char* argv[]) 
    { 
    bool bValidInput = false; 
    while (false == bValidInput) 
    { 
    cout << endl; 
    cout << "**********************************************" << endl; 
    cout << endl; 
    cout << "1 - Start Server to process incoming orders" << endl; 
    cout << "2 - Start Client to generate predefined orders" << endl; 
    cout << "0 - Quit" << endl; 
    cout << endl; 
    cout << "**********************************************" << endl; 
    cout << endl << "Which Test should be run? : "; 
    unsigned int uiAnswer; 
    cin >> uiAnswer; 
    switch (uiAnswer) 
        { 
        case 1 : {  ABCOrderProcessor OrderProcessor; 
            // Call ProcessIncomingOrders which will loop 
            //forever processing orders from clients. 
            OrderProcessor.ProcessIncomingOrders(); 
            break; 
        } 
        case 2 : { 
            // Send some orders 
            GenerateOrders(); 
            break; 
        } 
        case 0 : { 
            return 0; 
        } 
        } // switch 
          } //while 
        return 0; 
    } 
 
    void GenerateOrders() 
    { 
        abc_status sStatus; 
        // Create an Order Taker. 
        ABCOrderTaker OrderTaker; 
 
    // Create a sample book order and populate it with the 
    // ISBN 49, Price and Title 
    ABCBook Book; 
    Book.AddOrder( 49, 12345, "Everything to the Internet", 
                                        "Michael Capellas"); 
    // Send this book order to the server for processing. 
    // note: This will be txn #1 
        cout << endl << "Transaction # 1" <<endl; 
        sStatus = OrderTaker.SendOrder(&Book); 
        cout << endl; 
    // Reset the stream. This way we will reuse the beginning of 
    // the buffer that the stream manages. 
    Book.ResetStream(); 
 
        // Send another order to a server which handles ISBN 99 
    Book.AddOrder( 99, 56789, "Java How To Program", 
                                      "Deitel & Deitel"); 
 // Send this book order to the server for processing. 
        // note: This will be txn #2 
        cout << endl << "Transaction # 2" <<endl; 
        sStatus = OrderTaker.SendOrder(&Book); 
        cout << endl; 
 
        ABCMagazine Magazine; 
 
    Magazine.AddOrder(29,"PC Week","ZIFF-DAVIS", "February 2000"); 
 
        // Send this book order to the server for processing. 
        // note: This will be txn #3 
        cout << endl << "Transaction # 3" <<endl; 
        sStatus = OrderTaker.SendOrder(&Magazine); 
        cout << endl; 
    } 

6.2 Client Application ABCOrderTaker


    // ABCOrderTaker.cpp: implementation of the ABCOrderTaker class. 
    // 
    ////////////////////////////////////////////////////////////////////// 
 
    #include "ABCCommon.h" 
    #include "ABCOrderTaker.h" 
 
    ////////////////////////////////////////////////////////////////////// 
    // Construction/Destruction 
    ////////////////////////////////////////////////////////////////////// 
 
    ABCOrderTaker::ABCOrderTaker() : m_bRegistered(false) 
    { 
 
    } 
 
    ABCOrderTaker::~ABCOrderTaker() 
    { 
    
    } 
 
    abc_status ABCOrderTaker::SendOrder(ABCOrder *pOrder) 
    { 
        abc_status sStatus; 
    //  Register with RTR if we havn't already done so. 
    //  This will make sure we are ready to start sending data. 
        sStatus = Register(); 
        if (ABCSuccess != sStatus) return false; 
    // If we can't register with RTR then exit 
    // Start the Transaction 
        cout << "StartTransaction..." << endl; 
        sStatus = StartTransaction(); 
        print_status_on_failure(sStatus); 
    //   Send this Book Order object to a server capable 
    //   of processing it. 
        cout << "SendApplicationMessage..." << endl; 
 sStatus = SendApplicationMessage(pOrder); 
 print_status_on_failure(sStatus); 
 
    //   Let RTR know that this is the only object being sent 
    //   and that we are done with our work. 
        cout << "AcceptTransaction..." << endl; 
        sStatus = AcceptTransaction(); 
        print_status_on_failure(sStatus); 
 //   Determine if the server successfully processed the request 
            return DetermineOutcome(); 
        } 
    rtr_status_t ABCOrderTaker::Register() 
    { 
        rtr_status_t sStatus = RTR_STS_OK; 
    if(false == m_bRegistered) 
        { 
    //   If RTR is not already started then start it now. 
            sStatus = StartRTR();    
    //   Create a Facility if not already created. 
            sStatus = CreateFacility(); 
 
    //   Register our facility with RTR. 
            sStatus = RegisterFacility(ABCFacility); 
            print_status_on_failure(sStatus); 
    if(RTR_STS_OK == sStatus) 
            { 
                m_bRegistered = true; 
            } 


    // ABC Handlers 
        sStatus = RegisterHandlers(&m_rtrHandlers,&m_rtrHandlers); 
        print_status_on_failure(sStatus); 
        } 
        return sStatus; 
    } 
    abc_status ABCOrderTaker::DetermineOutcome() 
    { 
        RTRData  *pResult = NULL; 
        abc_status sStatus = ABCSuccess; 
 
        // Simply wait for RTR to send us an accepted or rejected. 
                
        // We can dispatch everything we get and let the default 
        // handlers process what we don't care about.  
        
        bool bDone = false; 
        while (!bDone) 
        { 
        sStatus = Receive(&pResult); 
        print_status_on_failure(sStatus); 
        sStatus = pResult->Dispatch(); 
        if (ABCOrderSucceeded == sStatus) 
        { 
        cout << "Transaction succeeded..." << endl; 
        bDone = true; 
        } 
        else 
            if (ABCOrderFailed == sStatus) 
            { 
            cout << "Transaction failed..." << endl; 
            bDone = true; 
            } 
        } 
    delete pResult; 
        return sStatus; 
    } 

6.3 Server Application ABCOrderProcessor


    // ABCOrderProcessor.cpp: implementation of the ABCOrderProcessor class. 
    // 
    ////////////////////////////////////////////////////////////////////// 
 
    #include "ABCCommon.h" 
    #include "ABCOrderProcessor.h" 
    #include <stdio.h> 
 
    ////////////////////////////////////////////////////////////////////// 
    // Construction/Destruction 
    ////////////////////////////////////////////////////////////////////// 
 
    ABCOrderProcessor::ABCOrderProcessor() 
    { 
 
    } 
 
    ABCOrderProcessor::~ABCOrderProcessor() 
    { 
    
    } 
 
    void ABCOrderProcessor::ProcessIncomingOrders() 
    { 
    //   Register with RTR. This will make sure we are ready to 
    //   start receiving data. 
        Register(); 
    //   Start processing orders 
        abc_status sStatus = RTR_STS_OK; 
        RTRData *pOrder = NULL; 
 
        while (1) 
        { 
    //   Receive an Order 
        sStatus = Receive(&pOrder); 
        print_status_on_failure(sStatus); 
        if(ABCSuccess != sStatus) break; 
        // if we can't get an Order then stop processing. 
 
    // Dispatch the Order to be processed 
    // note: This could be any kind of data. ie. RTRMessage RTREvent, 
    // RTRApplicationMessage or RTRApplicationEvent. 
    // The class ABCOrder(derived from RTRApplicationMessage) has 
    // redefined the Dispatch() method to call the Process() method 
    // of its derived class (ABCBook or ABCMagazine). All other 
    // data classes use the default implemenation of Dispatch() 
    // which will call the appropriate handler. 
            sStatus = pOrder->Dispatch(); 
            print_status_on_failure(sStatus); 
    // Check to see if there were any problems processing the order. 
    // If so, let the handler know to reject this txn when asked to 
    // vote. 
    // note : For the ABC company, orders are processed in the 
    // Process() method of all ABCOrder derived classed. 
            CheckOrderStatus(sStatus); 
 
    //   Delete this order that was allocated by the class factory. 
    // note: In this sample the class factory returns a separate 
    // instance of an order each time it is called. 
            delete pOrder; 
        } 
    return; 
 } 
 void ABCOrderProcessor::Register() 
    { 
        rtr_status_t sStatus; 
 
        // Create an environment that our server can run in. 
        CreateRTREnvironment(); 
 
        // Register with RTR the following objects 
        sStatus = RegisterFacility(ABCFacility); 
        print_status_on_failure(sStatus); 
 
        // ABC Partition 
        sStatus = RegisterPartition(ABCPartition1); 
        print_status_on_failure(sStatus); 
 
        sStatus = RegisterPartition(ABCPartition2); 
        print_status_on_failure(sStatus); 
 
        // ABC Class Factory 
        sStatus = RegisterClassFactory(&m_ClassFactory); 
        print_status_on_failure(sStatus); 
 
        // ABC Server Handlers 
        sStatus = RegisterHandlers(&m_rtrHandlers,&m_rtrHandlers); 
        print_status_on_failure(sStatus); 
 
        return; 
    } 
 
    void ABCOrderProcessor::CreateRTREnvironment() 
    { 
        rtr_status_t sStatus; 
        // If RTR is not already started then start it now. 
        StartRTR();    
        // Create a Facility if not already created. 
        CreateFacility(); 
        // Create a partition that processes ISBN numbers in the 
        // range 0 - 99 
        unsigned int low = 0; 
        unsigned int max = 99; 
        RTRKeySegment KeyZeroTo99(  rtr_keyseg_unsigned, 
                                    sizeof(int),        
                                         0,      
                                         &low,    
                                         &max ); 
        RTRPartitionManager PartitionManager; 
        sStatus = PartitionManager.CreateBackendPartition(  
                                                ABCPartition1, 
                                                ABCFacility,    
                                                KeyZeroTo99, 
                                                false, 
                                                true, 
                                                false); 
        print_status_on_failure(sStatus); 
 
        // Create a partition that processes ISBN numbers in the 
        // range 100 - 199 
        low = 100; 
        max = 199; 
        RTRKeySegment Key100To199(  rtr_keyseg_unsigned, 
                                    sizeof(int),     
                                         0,         
                                         &low,   
                                         &max ); 
        sStatus = PartitionManager.CreateBackendPartition(  
                                                   ABCPartition2, 
                                                   ABCFacility,    
                                                   Key100To199, 
                                                   false, 
                                                   true, 
                                                   false); 
        print_status_on_failure(sStatus); 
    } 
 
 
    void ABCOrderProcessor::CheckOrderStatus (abc_status sStatus) 
    { 
    // Check to see if there were any problems processing the order. 
    // If so, let the handler know to reject this transaction when 
    // asked to vote. 
        if (sStatus == ABCOrderFailed) 
        {    
    // Let the handler know that the current txn should be rejected    
            GetHandler()->OnABCOrderNotProcessed(); 
        }; 
 
    } 

6.4 Data Class ABCOrder


    // ABCOrder.cpp: implementation of the ABCOrder class. 
    // 
    ////////////////////////////////////////////////////////////////////// 
 
    #include "ABCCommon.h" 
    #include "ABCOrder.h" 
 
    ////////////////////////////////////////////////////////////////////// 
    // Construction/Destruction 
    ////////////////////////////////////////////////////////////////////// 
 
    ABCOrder::ABCOrder() : m_uiPrice(0) 
    { 
        m_szTitle[0] = '\0'; 
        m_szAuthor[0] = '\0'; 
    } 
 
    ABCOrder::~ABCOrder() 
    { 
 
    } 
 
    rtr_status_t ABCOrder::Dispatch() 
    { 
        // Populate the derived object 
        ReadObject(); 
    // Since we have overridden Dispatch() in our base class 
    // (RTRApplictaionMessage), the handler will not be called 
    // unless we do it ourselves. If we call our base class Dispatch 
    // method the handler methods OnInitialize() and 
    // OnApplictionMessage() will be called. This sample uses 
    // OnInitialize() to print out notification that a new 
    // transaction 
    // is starting. 
        RTRApplicationMessage::Dispatch(); 
    // Process the purchase which the derived object represents 
        abc_status status = ProcessOrder(); 
    return status; 
    } 

6.5 Data Class ABCBook


    // ABCBook.cpp: implementation of the ABCBook class. 
    // 
    ////////////////////////////////////////////////////////////////////// 
 
    #include "ABCCommon.h" 
    #include "ABCBook.h" 
 
    ////////////////////////////////////////////////////////////////////// 
    // Construction/Destruction 
    ////////////////////////////////////////////////////////////////////// 
 
    ABCBook::ABCBook() : m_uiISBN(0) 
    { 
 
    } 
 
    ABCBook::~ABCBook() 
    { 
 
    } 
 
 
    bool ABCBook::AddOrder( unsigned int uiPrice, 
                            unsigned int uiISBN, 
                            char *pszName, 
                            char *pszAuthor) 
    { 
    //  Copy the Book purchase to our Book object. 
        m_uiISBN = uiISBN; 
        m_uiPrice = uiPrice; 
        strcpy(&m_szTitle[0],pszName); 
        strcpy(&m_szAuthor[0],pszAuthor); 
        WriteObject(); 
        return true; 
    } 
 void ABCBook::WriteObject() 
 { 
 // Save the type of object we are. This is used by the 
 // class factory on the server side to determine which type 
 // of class to allocate. 
 *this << ABC_BOOK; 
 *this << m_uiPrice << m_uiISBN  << m_szTitle << m_szAuthor; 
 // The 1 line call above is equivalent to the 4 lines below. We 
 // can use the << and >> operators because we know that the data 
    // which we store is not > the current RTR maximum  = 65535 byes. 
    // WriteToStream(m_uiISBN); 
    // WriteToStream(m_uiPrice); 
    // WriteToStream(m_szTitle); 
    // WriteToStream(m_szAuthor); 
        char mystring[] = "ABCDEFGHIJKLMNOPQRSTUVWZYZ"; 
        rtr_msgbuf_t p = &mystring[0]; 
        rtr_msglen_t length = strlen(mystring)+1; 
        WriteToStream(p,length); 
    } 
    void ABCBook::ReadObject() 
    { 
    // The first data is the type of class we should be. 
    // Validate that everything is fine. 
        unsigned int uiClassType = 0; 
        *this >> uiClassType; 
        assert(uiClassType == ABC_BOOK); 
    //  Populate this object with the data 
        *this >> m_uiPrice >> m_uiISBN  >> m_szTitle >> m_szAuthor; 
    // The 1 line call above is equivilant to the 4 lines below. 
    // ReadFromStream(m_uiISBN); 
    // ReadFromStream(m_uiPrice); 
    // ReadFromStream(m_szTitle,GetLogicalBufferLength()); 
    // ReadFromStream(m_szAuthor,GetLogicalBufferLength()); 
    } 
    abc_status ABCBook::ProcessOrder() 
    { 
        // It is here that we would process the request for this book. 
        // For this sample simply print out the Book order. 
    cout <<"ABCBook::ProcessOrder()" << endl; 
        cout << "     " << "ISBN = " << m_uiISBN << endl; 
        cout << "     " << "Price = " << m_uiPrice << endl; 
        cout << "     " << "Title = " << m_szTitle << endl; 
        cout << "     " << "Author = " << m_szAuthor << endl; 
 
        return ABCOrderSucceeded; 
    } 
}


Index Contents