 |
 |
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
|  |
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.
|
|
 |
 |
 |
 |
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 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 );
}
|
|
 |
 |
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.
|
 |
 |
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;
}
|
|
 |
 |
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;
}
|
|
 |
 |
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);
}
}
}
|
|
|
|