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