Initialization in Java

Every Ice-based application needs to initialize the Ice run time, and this initialization returns a com.zeroc.Ice.Communicator object.

Communicator is a local Java object that represents an instance of the Ice run time. Most Ice-based applications create and use a single Communicator object, although it is possible and occasionally desirable to have multiple Communicator objects in the same application.

You initialize the Ice run time by calling com.zeroc.Ice.Util.initialize, for example:

Java
public static void main(String[] args)
{
    com.zeroc.Ice.Communicator communicator = com.zeroc.Ice.Util.initialize(args);
    ...
}

Util.initialize accepts the argument vector that is passed to main by the operating system. The method scans the argument vector for any command-line options that are relevant to the Ice run time. If anything goes wrong during initialization, Util.initialize throws an exception.

The semantics of Java arrays prevents this simple Util.initialize from modifying the argument vector. You can use another overload of Util.initialize to receive an argument vector with all Ice-related arguments removed.

Once you no longer need a Communicator, you must call destroy on this Communicator. The destroy method is responsible for finalizing the instance of the Ice run time embodied by this Communicator. In particular, in an Ice server, destroy waits for operation implementations that are still executing to complete. In addition, destroy ensures that any outstanding threads are joined with and reclaims a number of operating system resources, such as file descriptors and memory. Never allow your application to terminate without calling destroy first.

The general shape of our main method becomes:

Java
public class App
{
    public static void main(String[] args)
    {
        int status = 0;
        com.zeroc.Ice.Communicator communicator = com.zeroc.Ice.Util.initialize(args);
        
        //
        // Register shutdown hook to destroy communicator during JVM shutdown
        //
        Runtime.getRuntime().addShutdownHook(new Thread(() -> { communicator.destroy(); })); 
 
        // ...
        System.exit(status);
    }
}

The only pitfall with the code above is if you neglect to call System.exit, the application will continue to run because the Communicator started non-daemon threads.

Another way to initialize and destroy a Communicator is with a try-with-resources statement:

Java
public class App 
{
    public static void main(String[] args) 
    {
        int status = 0;
        try(com.zeroc.Ice.Communicator communicator = com.zeroc.Ice.Util.initialize(args))
        {
            // ...
        } // communicator is destroyed automatically here
        System.exit(status);
    }
}

The Communicator interface implements java.lang.AutoCloseable: at the end of a try-with-resources statement, the communicator is closed (destroyed) automatically, without an explicit call to the destroy method.

If you initialize your communicator in a try-with-resources statement, you may also add a shutdown hook to destroy the communicator. destroy does not throw any exception and calling destroy multiple times is perfectly ok. A shutdown hook that calls destroy is useful to interrupt long-running Ice invocations when the application receives a user interrupt such as Ctrl-C.

See Also