Table of Contents Previous Next
Logo
The Ice Run Time in Detail : 32.2 Communicators
Copyright © 2003-2009 ZeroC, Inc.

32.2 Communicators

 
The main entry point to the Ice run time is represented by the local interface Ice::Communicator. An instance of Ice::Communicator is associated with a number of run-time resources:
• Client-side thread pool
The client-side thread pool (see Section 32.10) is used to process replies to asynchronous method invocations (AMI) (see Section 33.3), to avoid deadlocks in callbacks, and to process incoming requests on bidirectional connections (see Section 37.7).
• Server-side thread pool
Threads in this pool accept incoming connections and handle requests from clients. See Section 32.10 for more information.
• Configuration properties
Various aspects of the Ice run time can be configured via properties. Each communicator has its own set of such configuration properties (see Chapter 30).
• Object factories
In order to instantiate classes that are derived from a known base type, the communicator maintains a set of object factories that can instantiate the class on behalf of the Ice run time (see Section 6.14.5 and Section 10.14.4).
• Logger object
A logger object implements the Ice::Logger interface and determines how log messages that are produced by the Ice run time are handled (see Section 32.20).
• Statistics object
A statistics object implements the Ice::Stats interface and is informed about the amount of traffic (bytes sent and received) that is handled by a communicator (see Section 32.21).
• Default router
A router implements the Ice::Router interface. Routers are used by Glacier2 (see Chapter 43) to implement the firewall functionality of Ice.
• Default locator
A locator is an object that resolves an object identity to a proxy. Locator objects are used to build location services, such as IceGrid (see Chapter 39).
• Plug‑in manager
Plug‑ins are objects that add features to a communicator. For example, IceSSL (see Chapter 42) is implemented as a plug‑in. Each communicator has a plug‑in manager that implements the Ice::PluginManager interface and provides access to the set of plug‑ins for a communicator.
• Object adapters
Object adapters dispatch incoming requests and take care of passing each request to the correct servant.
Object adapters and objects that use different communicators are completely independent from each other. Specifically:
• Each communicator uses its own thread pool. This means that if, for example, one communicator runs out of threads for incoming requests, only objects using that communicator are affected. Objects using other communicators have their own thread pool and are therefore unaffected.
• Collocated invocations across different communicators are not optimized, whereas collocated invocations using the same communicator bypass much of the overhead of call dispatch.
Typically, servers use only a single communicator but, occasionally, multiple communicators can be useful. For example, IceBox (see Chapter 44) uses a separate communicator for each Ice service it loads to ensure that different services cannot interfere with each other. Multiple communicators are also useful to avoid thread starvation: if one service runs out of threads, this leaves the remaining services unaffected.
The interface of the communicator is defined in Slice. Part of this interface
looks as follows:
module Ice {
    local interface Communicator {
        string proxyToString(Object* obj);
        Object* stringToProxy(string str);
        Object* propertyToProxy(string property);
        Identity stringToIdentity(string str);
        string identityToString(Identity id);
        ObjectAdapter createObjectAdapter(string name);
        ObjectAdapter createObjectAdapterWithEndpoints(
                                            string name,
                                            string endpoints);
        void shutdown();
        void waitForShutdown();
        bool isShutdown();
        void destroy();
        // ...
    };
    // ...
};
The communicator offers a number of operations:
• proxyToString
stringToProxy
These operations allow you to convert a proxy into its stringified representation and vice versa.
Instead of calling proxyToString on the communicator, you can also use the ice_toString operation on a proxy to stringify it (see Section 32.11.2). However, you can only stringify non-null proxies that way—to stringify a null proxy, you must use proxyToString. (The stringified representation of a null proxy is the empty string.)
• propertyToProxy
This operation retrieves the configuration property with the given name and converts its value into a proxy (see Section 32.11.1). A null proxy is returned if no property is found with the specified name.
• identityToString
stringToIdentity
These operations allow you to convert an identity to a string and vice versa (see Section 32.5).
• createObjectAdapter
createObjectAdapterWithEndpoints
These operations create a new object adapter. Each object adapter is associated with zero or more transport endpoints.
Typically, an object adapter has a single transport endpoint. However, an object adapter can also offer multiple endpoints. If so, these endpoints each lead to the same set of objects and represent alternative means of accessing these objects. This is useful, for example, if a server is behind a firewall but must offer access to its objects to both internal and external clients; by binding the adapter to both the internal and external interfaces, the objects implemented in the server can be accessed via either interface.
An object adapter also can have no endpoint at all. In that case, the adapter can only be reached via collocated invocations originating from the same communicator as is used by the adapter.
Whereas createObjectAdapter determines its endpoints from configuration information (see Section 32.4.6), createObjectAdapterWithEndpoints allows you to specify the transport endpoints for the new adapter. Typically, you should use createObjectAdapter in preference to createObjectAdapterWithEndpoints. Doing so keeps transport-specific information, such as host names and port numbers, out of the source code and allows you to reconfigure the application by changing a property (and so avoid recompilation when a transport endpoint needs to be changed).
The newly-created adapter uses its name as a prefix for a collection of configuration properties that tailor the adapter’s behavior (see Section C.4). By default, the adapter prints a warning if other properties are defined having the same prefix, but you can disable this warning using the property Ice.Warn.UnknownProperties (see Section C.3).
• shutdown
This operation shuts down the server side of the Ice run time:
Operation invocations that are in progress at the time shutdown is called are allowed to complete normally. shutdown does not wait for these operations to complete; when shutdown returns, you know that no new incoming requests will be dispatched, but operations that were already in progress at the time you called shutdown may still be running. You can wait for still executing operations to complete by calling waitForShutdown.
Operation invocations that arrive after the server has called shutdown either fail with a ConnectFailedException or are transparently redirected to a new instance of the server (see Chapter 39).
Note that shutdown initiates deactivation of all object adapters associated with the communicator, so attempts to use an adapter once shutdown has completed raise an ObjectAdapterDeactivatedException.
• waitForShutdown
On the server side, this operation suspends the calling thread until the communicator has shut down (that is, until no more operations are executing in the server). This allows you to wait until the server is idle before you destroy the communicator.
On the client side, waitForShutdown simply waits until another thread has called shutdown or destroy.
 
• isShutdown
This operation returns true if shutdown has been invoked on the communicator. A return value of true does not necessarily indicate that the shutdown process has completed, only that it has been initiated. An application that needs to know whether shutdown is complete can call waitForShutdown. If the blocking nature of waitForShutdown is undesirable, the application can invoke it from a separate thread.
• destroy
This operation destroys the communicator and all its associated resources, such as threads, communication endpoints, object adapters, and memory resources. Once you have destroyed the communicator (and therefore destroyed the run time for that communicator), you must not call any other Ice operation (other than to create another communicator).
It is imperative that you call destroy before you leave the main function of your program. Failure to do so results in undefined behavior.
Calling destroy before leaving main is necessary because destroy waits for all running threads to terminate before it returns. If you leave main without calling destroy, you will leave main with other threads still running; many threading packages do not allow you to do this and end up crashing your program.
If you call destroy without calling shutdown, the call waits for all executing operation invocations to complete before it returns (that is, the implementation of destroy implicitly calls shutdown followed by waitForShutdown). shutdown (and, therefore, destroy) deactivates all object adapters that are associated with the communicator. Since destroy blocks until all operation invocations complete, a servant will deadlock if it invokes destroy on its own communicator while executing a dispatched operation.
On the client side, calling destroy while operations are still executing causes those operations to terminate with a CommunicatorDestroyedException.
Table of Contents Previous Next
Logo