VisiBroker for C++ Developer’s Guide : Developing an example application with VisiBroker

Developing an example application with VisiBroker
This section uses an example application to describe the development process for creating distributed, object-based applications for both Java and C++.
The code for the example application is provided in the bank_agent.html file. You can find this file in:
<install_dir>/examples/vbe/basic/bank_agent/
Development process
When you develop distributed applications with VisiBroker, you must first identify the objects required by the application. The following figure illustrates the steps to develop a sample bank application. Here is a summary of the steps taken to develop the bank sample:
1
IDL is the language that an implementer uses to specify the operations that an object will provide and how they should be invoked. In this example, we define, in IDL, the Account interface with a balance() method and the AccountManager interface with an open() method.
2
With the interface specification described in step 1, use the idl2java or idl2cpp compilers to generate the client-side stubs and the server-side classes for the implementation of the remote objects.
3
To complete the implementation of the client program, initialize the VisiBroker ORB, bind to the Account and the AccountManager objects, invoke the methods on these objects, and print out the balance.
4
To complete the implementation of the server object code, we must derive from the AccountPOA and AccountManagerPOA classes, provide implementations of the interfaces' methods, and implement the server's main routine.
5
6
7
Figure 3
Step 1: Defining object interfaces
The first step to creating an application with VisiBroker is to specify all of your objects and their interfaces using the OMG's Interface Definition Language (IDL). The IDL can be mapped to a variety of programming languages.
You then use the idl2cpp compiler to generate stub routines and servant code compliant with the IDL specification. The stub routines are used by your client program to invoke operations on an object. You use the servant code, along with code you write, to create a server that implements the object.
Writing the account interface in IDL
IDL has a syntax similar to C++ and can be used to define modules, interfaces, data structures, and more.
The sample below shows the contents of the Bank.idl file for the bank_agent example. The Account interface provides a single member function for obtaining the current balance. The AccountManager interface creates an account for the user if one does not already exist.
module Bank{
interface
Account {
float balance();
};
interface AccountManager {
Account open(in string name);
};
};
Step 2: Generating client stubs and server servants
The interface specification you create in IDL is used by VisiBroker's idl2cpp to generate C++ stub routines for the client program, and skeleton code for the object implementation.
The client program uses the stub routines for all member function invocations.
You use the skeleton code, along with code you write, to create the server that implements the objects.
The code for the client program and server object, once completed, is used as input to your C++ compiler and linker to produce the client and server.
Because the Bank.idl file requires no special handling, you can compile the file with the following command.
prompt> idl2cpp Bank.idl
For more information on the command-line options for the idl2cpp compiler, see “Using IDL”
Files produced by the idl compiler
The idl2cpp compiler generates four files from the Bank.idl file:
Bank_c.hh: Contains the definitions for the Account and AccountManager classes.
Bank_c.cc: Contains internal stub routines used by the client.
Bank_s.hh: Contains the definitions for the AccountPOA and AccountManagerPOA servant classes.
Bank_s.cpp: Contains the internal routines used by the server.
You will use the Bank_c.hh and Bank_c.cpp files to build the client application. The Bank_s.hh and Bank_s.cpp files are for building the server object. All generated files have either a .cpp or .hh suffix to help you distinguish them from source files.
Windows
The default suffix for generated files from the idl2cpp compiler is .cpp. However, the Makefiles associated with the examples for VisiBroker Edition use the -src suffix to change the output to the specified extension.
Caution
You should never modify the contents of files generated by the idl2cpp compiler.
Step 3: Implementing the client
Many of the classes used in implementing the bank client are contained in the Bank code generated by the idl2cpp compiler as shown in the previous example.
The Client.C file illustrates this example and is included in the bank_agent directory. Normally, you would create this file.
Client.C
The Client program implements the client application which obtains the current balance of a bank account. The bank client program performs these steps:
1
2
Binds to an AccountManager object.
3
Obtains the balance of the Account using the object reference returned by bind().
4
Obtains the balance by invoking balance on the Account object.
#include Bank_c.hh
int main(int argc, char* const* argv) {
try {
// Initialize the ORB.
CORBA::ORB_ptr orb = CORBA::ORB_init(argc, argv);
// Get the manager Id
PortableServer::ObjectId_var managerId =
PortableServer::string_to_ObjectId(BankManager);
// Locate an account manager. Give the full POA name and servant ID.
Bank::AccountManager_ptr manager =
Bank::AccountManager::_bind(/bank_agent_poa, managerId);
// use argv[1] as the account name, or a default.
const char* name = argc > 1 ? argv[1] : Jack B. Quick;
// Request the account manager to open a named account.
Bank::Account_ptr account = manager->open(name);
// Get the balance of the account.
float balance = account->balance();
// Print out the balance.
cout << The balance in << name << 's account is $ << balance << endl;
} catch(const CORBA::Exception& e) {
cerr << e << endl;
}
}
Binding to the AccountManager object
Before your client program can invoke the open(String name) member function, the client must first use the bind() member function to establish a connection to the server that implements the AccountManager object.
The implementation of the bind() member function is implemented automatically by idl2cpp. The bind() member function requests the VisiBroker ORB to locate and establish a connection to the server.
If the server is successfully located and a connection is established, a proxy object is created to represent the server's AccountManagerPOA object. A pointer is returned to your client program.
Obtaining an Account object
Next, your client program needs to call the open() member function on the AccountManager object to get a pointer to the Account object for the specified customer name.
Obtaining the balance
Once your client program has established a connection with an Account object, the balance() member function can be used to obtain the balance. The balance() member function on the client side is actually a stub generated by the idl2cpp compiler that gathers all the data required for the request and sends it to the server object.
Several other member functions are provided that allow your client program to manipulate an AccountManager object reference.
Step 4: Implementing the server
Just as with the client, many of the classes used in implementing the bank server are contained in the header files of Bank generated by the idl2cpp compiler. The Server.C file is a server implementation included for the purposes of illustrating this example. Normally you, the programmer, would create this file.
Server programs
This file implements the Server class for the server side of our banking example. The code sample below ia an example of a server side program. The server program does the following:
#include BankImpl.h
int main(int argc, char* const* argv) {
try {
// Initialize the ORB.
CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);
// get a reference to the root POA
CORBA::Object_var obj = orb->resolve_initial_references(RootPOA);
PortableServer::POA_var rootPOA = PortableServer::POA::_narrow(obj);
CORBA::PolicyList policies;
policies.length(1);
policies[(CORBA::ULong)0] =
rootPOA->create_lifespan_policy(PortableServer::PERSISTENT);
// get the POA Manager
PortableServer::POAManager_var poa_manager =
rootPOA->the_POAManager();
// Create myPOA with the right policies
PortableServer::POA_var myPOA = rootPOA->create_POA(bank_agent_poa,
poa_manager, policies);
// Create the servant
AccountManagerImpl managerServant;
// Decide on the ID for the servant
PortableServer::ObjectId_var managerId =
PortableServer::string_to_ObjectId(BankManager);
// Activate the servant with the ID on myPOA
myPOA->activate_object_with_id(managerId, &managerServant);
// Activate the POA Manager
poa_manager->activate();
cout << myPOA->servant_to_reference(&managerServant) << is ready
<< endl;
// Wait for incoming requests
orb->run();
} catch(const CORBA::Exception& e) {
cerr << e << endl;
return 1;
}
return 0;
}
Understanding the Account class hierarchy
The Account class that you implement is derived from the POA_Bank::Account class that was generated by the idl2cpp compiler. Look closely at the POA_Bank::Account class definition that is defined in the Bank_c.hh file and notice that it is derived from the Account class. The figure below shows the class hierarchy.
Figure 4
Step 5: Building the example
The examples directory of your VisiBroker Edition release contains a Makefile.cpp for this example and other VisiBroker examples.
The Client.C that you created and the generated Bank_c.cc file are compiled and linked together to create the client program. The Server.C file that you created, along with the generated Bank_s.cpp and the Bank_c.cpp files, are compiled and linked to create the bank account server. Both the client program and the server must be linked with the VisiBroker ORB library.
Note:
The examples directory also contains a file named stdmk (for UNIX) or stdmk_nt (for Windows NT), and defines file location and variable settings to be used by the Makefile.
You may need to customize the stdmk or stdmk_nt file if your compiler does not support the specified flags.
Compiling the example
Windows
Assuming VisiBroker is installed in C:\vbroker, type the following to compile the example:
prompt> C:
prompt> cd vbroker\examples\basic\bank_agent
prompt> nmake -f Makefile.cpp
The Visual C++ nmake command runs the idl2cpp compiler and then compiles each file.
If you encounter some problems while running make, check that your path environment variable points to the bin directory where you installed the VisiBroker Edition software.
Also, try setting the VBROKERDIR environment variable to the directory where you installed the VisiBroker Edition software.
UNIX
Assuming VisiBroker is installed in /usr/local, type the following to compile the example:
prompt> cd /usr/local/vbroker/examples/basic/bank_agent
prompt> make cpp
In this example, make is the standard UNIX facility. If you do not have it in your PATH, see your system administrator.
Step 6: Starting the server and running the example
Now that you have compiled your client program and server implementation, you are ready to run your first VisiBroker application.
Starting the Smart Agent
Before you attempt to run VisiBroker Edition client programs or server implementations, you must first start the Smart Agent on at least one host in your local network.
The basic command for starting the Smart Agent is as follows:
prompt> osagent
The Smart Agent is described in detail in “Using the Smart Agent”
Starting the server
Windows
Open a DOS prompt window and start your server by typing:
prompt> start Server
UNIX
Start your Account server by typing:
prompt> Server&
Running the client
Windows
Open a separate DOS prompt window and start your client by typing:
prompt> Client
UNIX
To start your client program, type:
prompt> Client
You should see output similar to that shown below (the account balance is computed randomly).
The balance in the account in $168.38.
Deploying applications with VisiBroker Edition
VisiBroker is also used in the deployment phase. This phase occurs when a developer has created client programs or server applications that have been tested and are ready for production. At this point a system administrator is ready to deploy the client programs on end-users' desktops or server applications on server-class machines.
For deployment, the VisiBroker ORB supports client programs on the front end. You must install the VisiBroker ORB on each machine that runs the client program. Clients (that make use of the VisiBroker ORB) on the same host share the VisiBroker ORB. The VisiBroker ORB also supports server applications on the middle tier. You must install the full VisiBroker ORB on each machine that runs the server application. Server applications or objects (that make use of the VisiBroker ORB) on the same server machine share the VisiBroker ORB. Clients may be GUI front ends, applets, or client programs. Server implementations contain the business logic on the middle tier.
Figure 5
VisiBroker Applications
Deploying applications
In order to deploy applications developed with VisiBroker, you must first set up a runtime environment on the host where the application is to be executed and ensure that the necessary support services are available on the local network.
The runtime environment required for applications developed with VisiBroker for C++ includes these components:
The VisiBroker libraries, located in the bin sub-directory where the product is installed.
The VisiBroker ORB libraries must be installed on the host where the deployed application is to execute. The location of these libraries must be included in the PATH for the application's environment.
Environment variables
If the deployed application is to use a Smart Agent (osagent) on a particular host, you must set the OSAGENT_ADDR environment variable before running the application. You can use the ORBagentAddr property as a command-line argument to specify a hostname or IP address. The table in “Support service availability” lists the necessary command-line arguments.
If the deployed application is to use a particular UDP port when communicating with a Smart Agent, you must set the OSAGENT_PORT environment variable before running the application.
You can use the ORBagentPort (C++) command-line argument to specify the IP port number.
For more information about environment variables, see the VisiBroker Installation Guide.
Support service availability
A Smart Agent must be executing somewhere on the network where the deployed application is to be executed. Depending on the requirements of the application being deployed, you may need to ensure that other VisiBroker runtime support services are available, as well. These services include:
Running the application
Before you attempt to run VisiBroker Edition client programs or server implementations, you must first start the Smart Agent on at least one host in your local network. The Smart Agent is described in detail in “Using the Smart Agent”
Executing client applications
A client application is one that uses VisiBroker ORB objects, but does not offer any VisiBroker ORB objects of its own to other client applications.
The following table summarizes the command-line arguments that may be specified for a client application. These arguments also are applicable to servers.
If set to 1, this option specifies that support for the 1.0 IDL-to-C++ mapping should be provided. If set to 0 or not specified at all, the new 1.1 mapping will be used. The default setting is 0. If -ORBbackcompat is set to 1, this option will automatically be set to 1.
Specifies the name of the Interface Repository to be accessed when the Object::get_interface() method is invoked on object implementations.
Specifies the IOR of the Interface Repository to be accessed when the Object::get_interface() method is invoked on object implementations.
If set to 1, this option specifies that the VisiBroker ORB will allow C++ NULL strings to be streamed. The NULL strings will be marshaled as strings of length 0 opposed to the empty string (“”) which is marshaled as a string of length 1, with the sole character of \0. If set to 0, attempts to marshal out a NULL string will throw CORBA::BAD_PARAM. Attempts to marshal in a NULL string will throw CORBA::MARSHAL. The default setting is 0. If -ORBbackcompat is set to 1, this option will automatically be set to 1.
When set to 1, it sets all sockets to immediately send requests. The default value of 0 allows sockets to send requests in batches as buffers fill. This argument can be used to significantly impact performance or benchmark results.