Implementing ostcDisconnect()

You can use ostcDisconnect() to perform application-specific processing whenever the Server is about to shut down.

You must implement this function, even if there is no such processing to perform.

Example

// You must implement ostcDisconnect, even if as a no-op

void ostcDisconnect(void)
{
}

QuickStart Example

In your Framework installation directory, examples/ostc/quickstart contains the source for a simple application that performs various operations on bank accounts. This chapter describes the application, focusing on an operation that transfers funds from one account to another.

examples/ostc/quickstart contains these two subdirectories:

Client Header File

This thin client uses one header file, quickstartclient.h, which declares the following classes:

One way to modularize thin clients is to define one class, like QuickStartClient, for each component the client uses. This client uses a single component that supports all the operations.

All thin clients must include ostc.h:

#include <ostc.h>

Client Source Files

The thin client uses two .cpp files:

clientmain.cpp

clientmain.cpp instantiates QuickStartClient and QuickStartDisplay (on the stack), and starts the I/O event loop. The main program also uses the Client API to set the router:

// Main program for the client
// Must specify router host:port pair as argument

#include <stdio.h>
#include "quickstartclient.h"

int main(int argc, char ** argv)
{
      ...
      // Set the router
      ostc::addRouter(argv[1]);
      ...
}

quickstartclient.cpp

quickstartclient.cpp implements members of QuickStartClient and QuickStartDisplay. The constructor and destructor connect and disconnect from a Server:

#include <stdio.h>
#include "quickstartclient.h"

// Construction/Destruction
QuickStartClient::QuickStartClient()
{
      // Connect to the server
      _session = ostc::connect("quickstart");
}

QuickStartClient::~QuickStartClient()
{
      // Disconnect from the server
      ostc::disconnect(_session);
}

Here is QuickStartDisplay::transfer(), which is called from the event loop (in QuickStartDisplay::run()). It accepts input for the name of the account to which to transfer the funds, the name of the account from which to transfer the funds, and the transfer amount.

It passes these to QuickStartClient::transfer(), which returns the result in the form of a list of ostc_Objects. Then it uses the Client API to extract the results.

void QuickStartDisplay::transfer()
{
      // Input from_name, to_name, and amount
      ...

      // Call QuickStartClient::transfer()
      ostc_ObjectList * result = 
            _client->transfer(from_name, to_name, amount);

      ...

      // Extract the results

      ostc_Object * account = 0;

      account = result->first();
      printf(
            "%-20.15s%15f\n",
            account->getStringValue("name"),
            account->getFloatValue("val")
      );

      account = result->next();
      printf(
            "%-20.15s%15f\n",
            account->getStringValue("name"),
            account->getFloatValue("val")
      );

      ...
}

Here is QuickStartClient::transfer(). It receives from_name, to_name, and amount from QuickStartDisplay::transfer(). The function uses the client API to

The function returns the result in the form of a list of ostc_Objects.

ostc_ObjectList * QuickStartClient::transfer(
      char * from_name, 
      char * to_name, 
      float amount
)
{
      // Get the transfer operation
      ostc_Operation * transfer = _session->getOperation("transfer");
      if ( !transfer )
             return 0;

      // Set up the arguments
      transfer->setArgument("from_acct_name", from_name);
      transfer->setArgument("to_acct_name", to_name);
      transfer->setArgument("amount", amount);

      // Execute the operation without using the cache
      ostc_ObjectList * result = _session->doOperation(transfer,0);

      if (!result) {
            return 0;
      }
      else {
            return result;
      }
}

Component Header Files

The Server plug-in uses the following header files:

ostcinterface.h

The plug-in header should include ostcsrvr.h:

#include <osctsrvr.h>

You must declare three global functions:

// Forward declarations
class ostc_ServerSession;

extern "C" { 

#ifdef WIN32
__declspec( dllexport )  void ostcInitialize();
__declspec( dllexport )  void ostcConnect(ostc_ServerSession *);
__declspec( dllexport )  void ostcDisconnect(void);
#else
void ostcInitialize();
void ostcConnect(ostc_ServerSession *);
void ostcDisconnect(void);
#endif
}

This use of _declspec is required for Windows platforms.

ostcoperations.h

The Server plug-in defines one subtype of ostc_ServerOperation for each operation it supports. Here is the one corresponding to the transfer operation:

class txfer_operation : public ostc_ServerOperation
{
public:
      txfer_operation(QuickStart*);
      ~txfer_operation() {}

      void execute(ostc_Object * Arguments, ostc_OperationResult*);
      void format(
            const void*, 
            ostc_ObjectList*, 
            ostc_OperationResult*
      );

private:
      QuickStart * _app;
};

Server Plug-in Source Files

The plug-in uses the following .cpp files:

ostcinterface.cpp

ostcInitialize() instantiates QuickStart, which instantiates the operation subtypes, opens or creates a database, and retrieves a root:

// This function is called once at server start-up
void ostcInitialize()
{
      // Generate an instance of the app
      if (!QuickStart::theServer)
            QuickStart::theServer = new QuickStart();

}

ostcConnect() registers the operation objects with the session:

// This function is also called once at start-up. 
void ostcConnect(ostc_ServerSession * session)
{
      // Add the QuickStart operations to the server
      QuickStart::theServer->addOperations(session);
}

ostcDisconect() performs cleanup:

// This function is called once when the server is being shut down
void ostcDisconnect(void)
{

      // If we have no more connections then delete the QuickStart
      if (QuickStart::theServer)
            delete QuickStart::theServer;
}

quickstart.cpp

This is called by ostcInitialize():

QuickStart::QuickStart()
{
      // The member initialize() opens or creates db and gets root
      initialize(example_db_name);

      // Create all of the server operations
      _addAccount = new AddAccount(this);
      _withdraw = new withdraw(this);
      _deposit = new deposit(this);
      _balance = new balance(this);
      _transfer = new txfer_operation(this);
}

This is called by ostcConnect():

// Adds Server operations to the session
void QuickStart::addOperations(ostc_ServerSession * session)
{
      // Add all the operations to all servers for this service
      session->addOperation(_addAccount);
      session->addOperation(_withdraw);
      session->addOperation(_deposit);
      session->addOperation(_transfer);
      session->addOperation(_balance);
}

ostcoperations.cpp

The operation subtype constructor specifies the operation name, transaction type, and formal parameters:

txfer_operation::txfer_operation(QuickStart * app) : 
      ostc_ServerOperation("transfer", ostc::isolated_update)
{
      // initialize 
      _app = app;

      addArgument("from_acct_name", ostc::ostc_string);
      addArgument("to_acct_name", ostc::ostc_string);
      addArgument("amount", ostc::ostc_float);
      addReturnSetAttribute("val", ostc::ostc_float);
      addReturnSetAttribute("name", ostc::ostc_string);
}

execute() performs the operation:

void txfer_operation::execute(
      ostc_Object * Arguments, 
      ostc_OperationResult* result
)
{
      const char* from_acct_name = 
            Arguments->getStringValue("from_acct_name");
      const char* to_acct_name = 
            Arguments->getStringValue("to_acct_name");
      float amount = 
            Arguments->getFloatValue("amount");

      Account * from_account = _app->getAccount(from_acct_name);
      Account * to_account = _app->getAccount(to_acct_name);

      _app->transfer(from_account, to_account, amount);

      os_collection *new_balances = 
            &os_collection::create(
                  os_segment::get_transient_segment()
            );

      new_balances->insert( from_account );
      new_balances->insert( to_account );

      result->setReturnValue(new_balances);
}

format() formats the operation results as Ostc_Objects:

void txfer_operation::format(
      const void * OSobj, 
      ostc_ObjectList * ostcList, 
      ostc_OperationResult*)
{
      Account * acct = (Account*)OSobj;

      ostc_Object * obj = ostcList->addObject();

      obj->setValue("name", acct->getName());
      obj->setValue("val", acct->getBalance());
}

Intermediate Example

This chapter discusses a sample application that allows end users to purchase tickets to a specified performance of a show such as a play, concert, or movie. The source code for the example is in /examples/ostc/ticketapp.

The thin client in this application allows the end user to perform the following actions:

There are also administrative actions for adding and removing shows, performances, and theaters.

Each of these actions corresponds to an ostc_ServerOperation defined by the Server plug-in in this example. The thin client assumes there are two Component Server processes running, one for read-only operations (ListShows, ListPerformances, and ViewSeats), and one for update operations (BuySeats and administrative actions).

The two Servers run the same service, but different transaction types, read and isolated_update, specified as command-line arguments to the Server executable.

When the thin client starts, it establishes a session with the service. When the user selects an action, the thin client uses the session to do the following:

Then the client redisplays the menu of actions.



[previous] [next]