Hosted by:

WrapperListener Integration

WrapperListener Integration

Integration Methods

- Methods of Integrating with the Java Service Wrapper

Method 3 - WrapperListener Integration

- Overview
- Detailed Instructions

| Overview

The third and final method, while providing the most flexibility and access to all of the Wrapper's features, is also the only one which requires some coding to complete the integration. This method involves creating a class which implements the `WrapperListener` interface. An instance of the user class is then instantiated and registered with the `WrapperManager`.

While this method provides features that are not available with either of the first two methods, it does add some complexity. If the additional features are not required, implementing a shutdown hook to enable the use of Method 1, or implementing a shutdown class should be considered as options. The main method of a shutdown class can be as simple as just calling a shutdown method in the application.

This method will explain how the `TestWrapper` application which ships with the Wrapper works.

NOTE MEG |  | This document will not cover the installation of the Wrapper files or scripts which will be used to launch the application. Both of these subjects are covered in detail in the descriptions of the first two integration methods.

| Detailed Instructions

| The Application Main Class

Before explaining the process in too much detail, we will start with an example main class and then explain each of its components. The code below is a simple class which implements the `WrapperListener` interface and contains a main method which instantiates the class and calls start on the `WrapperManager`. Give it a brief once over, we go through it step by step below.

    import org.tanukisoftware.wrapper.WrapperManager;
    import org.tanukisoftware.wrapper.WrapperListener;

    public class Main
        implements WrapperListener
    {
        private MyApp m_app;

        /*---------------------------------------------------------------
         * Constructors
         *-------------------------------------------------------------*/
        private Main()
        {
        }

        /*---------------------------------------------------------------
         * WrapperListener Methods
         *-------------------------------------------------------------*/
        /**
         * The start method is called when the WrapperManager is signaled by the
         *	native wrapper code that it can start its application.  This
         *	method call is expected to return, so a new thread should be launched
         *	if necessary.
         *
         * @param args List of arguments used to initialize the application.
         *
         * @return Any error code if the application should exit on completion
         *         of the start method.  If there were no problems then this
         *         method should return null.
         */
        public Integer start( String[] args )
        {
            m_app = new MyApp( args );
            m_app.start();

            return null;
        }

        /**
         * Called when the application is shutting down.  The Wrapper assumes that
         *  this method will return fairly quickly.  If the shutdown code code
         *  could potentially take a long time, then WrapperManager.signalStopping()
         *  should be called to extend the timeout period.  If for some reason,
         *  the stop method can not return, then it must call
         *  WrapperManager.stopped() to avoid warning messages from the Wrapper.
         *
         * @param exitCode The suggested exit code that will be returned to the OS
         *                 when the JVM exits.
         *
         * @return The exit code to actually return to the OS.  In most cases, this
         *         should just be the value of exitCode, however the user code has
         *         the option of changing the exit code if there are any problems
         *         during shutdown.
         */
        public int stop( int exitCode )
        {
            m_app.stop();

            return exitCode;
        }

        /**
         * Called whenever the native wrapper code traps a system control signal
         *  against the Java process.  It is up to the callback to take any actions
         *  necessary.  Possible values are: WrapperManager.WRAPPER_CTRL_C_EVENT,
         *    WRAPPER_CTRL_CLOSE_EVENT, WRAPPER_CTRL_LOGOFF_EVENT, or
         *    WRAPPER_CTRL_SHUTDOWN_EVENT
         *
         * @param event The system control signal.
         */
        public void controlEvent( int event )
        {
            if (WrapperManager.isControlledByNativeWrapper()) {
                // The Wrapper will take care of this event
            } else {
                // We are not being controlled by the Wrapper, so
                //  handle the event ourselves.
                if ((event == WrapperManager.WRAPPER_CTRL_C_EVENT) ||
                    (event == WrapperManager.WRAPPER_CTRL_CLOSE_EVENT) ||
                    (event == WrapperManager.WRAPPER_CTRL_SHUTDOWN_EVENT)){
                    WrapperManager.stop(0);
                }
            }
        }

        /*---------------------------------------------------------------
         * Main Method
         *-------------------------------------------------------------*/
        public static void main( String[] args )
        {
            // Start the application.  If the JVM was launched from the native
            //  Wrapper then the application will wait for the native Wrapper to
            //  call the application's start method.  Otherwise the start method
            //  will be called immediately.
            WrapperManager.start( new Main(), args );
        }
    }

| The Main Method

The main method should in most cases be extremely simple. It has the job of instantiating a class which implements `WrapperListener` instance and then passing that instance along with any arguments to the `start` method of the `WrapperManager` class. While it is not a strict rule, in general, the main method should do nothing else. All application initialization should be performed from within the `start` method.

        public static void main( String[] args )
        {
            // Start the application.  If the JVM was launched from the native
            //  Wrapper then the application will wait for the native Wrapper to
            //  call the application's start method.  Otherwise the start method
            //  will be called immediately.
            WrapperManager.start( new Main(), args );
        }

| Constructor

The constructor should usually be empty as it has to complete within the scope of the `main` method above. In general, the rule of doing nothing until the `start` method has been called should be followed.

        private Main()
        {
        }

| WrapperListener start Method

The `start` method is where things start to happen. This is called by the `WrapperManager` after it has established a connection with the Wrapper process. Once the Wrapper has confirmed that the Java process has been successfully launched and that the `WrapperManager` class has been loaded, it will request that the user application be started by calling the `WrapperListener.start` method.

In many ways, the `start` method can be thought of as replacing an application's `main` method. There are some differences that you will have to keep in mind however. The `start` method is called while the application is in its startup phase and the application will not be considered to have started until the `start` method has returned.

The Wrapper needs to be able to tell when an application has actually completed its startup in order to defer the launching of other processes which depend on the application being controlled by the Wrapper. This is currently only an issue with the Windows version, in cases where another NT Service has the Wrapper on its list of service dependencies. Those dependencies state that the Wrapper must be started before and stopped after the dependent service.

In this first example, the `start` method simply calls the `main` method of another class. Remember, this will only work if we know for sure that the main method will return within a few seconds.

        public Integer start( String[] args )
        {
            MyApp.main( args );

            return null;
        }

This next example instantiates an application's main class and then tells it to start up.

        public Integer start( String[] args )
        {
            m_app = new MyApp( args );
            m_app.start();

            return null;
        }

The return value of the start method gives the application a chance to abort the startup process before the application has actually been officially started. This can be important where dependent services are concerned. If you have such concerns then you must use this integration method. Both the `WrapperSimpleApp` and `WrapperStartStopApp` helper classes both call the application's main method in a background thread and report that the application has successfully started within a few seconds.

A return value of `null` indicates a successful startup, where as any `Integer` object is used to indicate the exit code which the Wrapper should return when it quits.

        public Integer start( String[] args )
        {
            m_app = new MyApp( args );
            m_app.start();
            if ( m_app.isOk() )
            {
                return null;
            }
            else
            {
                System.out.println( "MyApp startup failed." );
                return new Integer( 1 );
            }
        }

As stated above, the Wrapper assumes that the `start` method returns after the application has started. By default, the Wrapper will wait for 30 seconds for the start method to complete. This timeout can be set using the `wrapper.startup.timeout` property, but it is not always desirable to set that property to a large value.

For applications which take a variable amount of time to start up, the Wrapper provides a way for the application to report on its progress. At various points during the startup phase, user code can call `WrapperManager.signalStarting(waitHint)`. This method tells the Wrapper that startup is going well, but that additional time is required. It can be called as many times as needed.

        public Integer start( String[] args )
        {
            m_app = new MyApp( args );

            WrapperManager.signalStarting( 60000 );
            // Do something that takes a while

            WrapperManager.signalStarting( 60000 );
            // Do something else that also may take a while

            return null;
        }

| WrapperListener stop Method

The stop method is called by the Wrapper whenever the JVM needs to be shutdown. It will always be called, whether a user presses `CTRL-C`, the application is stopped via the NT service manager or from a script, or user code calls `System.exit` or `WrapperManager.stop`.

If there is some code in your application to perform a clean shutdown, it should be called from within this method, rather than having your shutdown code call `WrapperManager.stop`. This will guarantee that the shutdown code is always called at the correct time. Be aware that existing shutdown hooks will continue to work as always.

The `stop` method is called with the exit code that the Wrapper is planning on exiting with. You have the choice of returning this same exit code, or changing the exit code to reflect a problem while stopping the application.

        public int stop( int exitCode )
        {
            m_app.stop();

            return exitCode;
        }

As with the `start` method. There are times when the act of stopping an application may take longer than the time available in the default stop timeout. In such a case, you have the option of extending the stop timeout using the `wrapper.shutdown.timeout` property. Rather than changing this property, it is also possible to inform the Wrapper that more time is needed by calling the `WrapperManager.signalStopping(waitHint)` method.

        public int stop( int exitCode )
        {
            WrapperManager.signalStopping( 60000 );
            // Do some cleanup that takes a while

            WrapperManager.signalStopping( 60000 );
            // Do some more cleanup that takes a while

            return exitCode;
        }

| WrapperListener controlEvent Method

The `controlEvent` method is used to receive control events from the system. These include `CTRL-C` on all platforms, as well as events for when the user logs off or the machine wants to shutdown, under windows.

If most cases, the Wrapper will correctly handle all of these events and trigger the shutdown process. However, it is also possible to run the Java application directly without using the Wrapper. This can be done for testing or any number of reasons. In this case, it is the responsibility of the Java application to handle its own life-cycle.

The following example will trigger a shutdown of the JVM if the user presses `CTRL-C`, hits the close box, logs out, or shuts down the machine. But only if not controlled by the Wrapper.

        public void controlEvent( int event )
        {
            if (WrapperManager.isControlledByNativeWrapper()) {
                // The Wrapper will take care of this event
            } else {
                // We are not being controlled by the Wrapper, so
                //  handle the event ourselves.
                if ((event == WrapperManager.WRAPPER_CTRL_C_EVENT) ||
                    (event == WrapperManager.WRAPPER_CTRL_CLOSE_EVENT) ||
                    (event == WrapperManager.WRAPPER_CTRL_SHUTDOWN_EVENT)){
                    WrapperManager.stop(0);
                }
            }
        }

by Leif Mortenson

Copyright ©1999-2004 by Tanuki Software. All Rights Reserved. | last modified: