C++ Clients

The chat demo includes two simple command-line clients written in C++. The first client uses the push model and demonstrates how to implement an Ice object to receive callbacks from the chat server, and how to create and use a Glacier2 session. The second client (not shown here) uses the pull model. The code snippets below were adapted from the push client to give you a peek into an Ice for C++ program; if you want to see the entire source code for either of the clients, we encourage you to download the source archive for the chat application.

Push Client

Using a Glacier2 router requires a fair amount of boilerplate code that is often duplicated in each program. To simplify the creation of Glacier2 command-line applications and minimize this code duplication, Ice includes the Glacier2::Application helper class. Our C++ client subclasses Glacier2::Application and overrides two pure virtual functions: createSession and runWithSession.

The createSession method is responsible for creating a new Glacier2 session. Our implementation prompts for a user name and password and then invokes createSession on the router proxy:

C++
string user = ...;
string password = ...;
auto session = router()->createSession(user, password);

This code is making use of the router convenience method, which returns a router proxy that is obtained from the program's configuration properties.

After createSession completes successfully, the base class invokes runWithSession to execute the program's main loop. Our implementation of runWithSession starts by down-casting the session proxy:

C++
auto session = Ice::uncheckedCast<Chat::ChatSessionPrx>(this->session());

The session convenience method returns the proxy for the session that we created in createSession. Since this is a proxy of type Glacier2::Session, we narrow it to the derived interface Chat::ChatSession that we saw earlier. We use uncheckedCast here to avoid sending a confirmation request to the target object because the client already knows that the target object implements the desired interface.

Now we can invoke the setCallback operation on the ChatSession interface to join the chat room:

C++
session->setCallback(Ice::uncheckedCast<Chat::ChatRoomCallbackPrx>(addWithUUID(make_shared<ChatRoomCallbackI>())));

There's a lot happening in this short snippet of code. First, we instantiate our callback servant class ChatRoomCallbackI and pass it to the addWithUUID convenience function. This function registers our servant with an object adapter intended especially for callback objects, creating that object adapter if it doesn't already exist. addWithUUID also ensures that the object identity associated with the servant includes a UUID and complies with Glacier2's conventions for callback objects. We narrow the resulting callback proxy to the type Chat::ChatRoomCallback using another unchecked cast, and finally pass this proxy to the setCallback operation.


From now on, any events that occur in the chat room will be relayed to our callback servant, which prints an appropriate message to the console. Our main loop simply prompts for new chat messages until the user elects to quit:

C++
do
{
    string s;
    getline(cin, s);
    if(s == "/quit")
        break;
    session->send(s);
} while(cin.good());

Meanwhile, the Glacier2::Application class takes care of mundane details such as keeping the session alive, recovering from errors, and automatically restarting the session when possible.