import java.util.Observer; import java.util.Observable; /** *
SignalTest serves two purposes:
* *Merely instantiating this object (and hanging onto a reference * to it) is enough to enable the signal handling.
**/ public class SignalTest implements Observer { /** * The software's entry point; exits after 10 seconds. * @param args Any and all arguments are ignored and have no effect. **/ public static void main( final String[] args ) { new SignalTest().go(); } private void go() { final SignalHandler sh; try { sh = new SignalHandler(); sh.addObserver( this ); sh.handleSignal( "HUP" ); System.out.println( "Sleeping for 10 seconds: hit me with signals!" ); Thread.sleep( 10000 ); } catch( Throwable x ) { // SignalHandler failed to instantiate: maybe the classes do not exist, // or the API has changed, or something else went wrong; actualy we get // here on an InterruptedException from Thread.sleep, too, but that is // probably quite rare and doesn't matter in a simple demo like this. x.printStackTrace(); } } /** * Implementation of Observer, called by {@link SignalHandler} when * a signal is received. * @param o Our {@link SignalHandler} object * @param arg The {@link sun.misc.Signal} that triggered the call **/ public void update( final Observable o, final Object arg ) { // use the same method that the Timer employs to trigger a // rotation, which ensures that signal and timer don't screw // each other up. System.out.println( "Received signal: "+arg ); } } /** *This class depends completely on Sun * Microsystems' signal handling classes in the sun.misc * package. Caveat emptor!
* *An implementation of Sun Microsystems' {@link * sun.misc.SignalHandler} interface that is also {@link Observable} * so that we can notify {@link Observer}S when a signal is raised. * The {@link #handle(sun.misc.signal)} method is called by Sun's * libraries for every signal received that was registered with a call * to Sun's static {@link * sun.misc.Signal#handle(sun.misc.Signal,sun.misc.SignalHandle)} * method.
* *Yes, we could have created an Event object and used the * addListener/removeListener methodology just the same, but * Observer/Observable is easier to use and read in simple cases and * demonstrates what we care to teach. You are more than welcome to * improve on the design.
* *The enterprising developer might redesign (or complicate) this * class with dynamic discovery of API methods, potential use of a * configuration class to specify method signatures, class names, * etc. in order to build for future compatibility or maybe just * because Java lets you do that sort of thing with relative ease.
**/ class SignalHandler extends Observable implements sun.misc.SignalHandler { /** * Tells the object to handle the given signal. * @param signalName The name of the signal, such as "SEGV", "ILL", * "FPE", "ABRT", "INT", "TERM", "HUP", etc. Not all platforms * support all signals. Microsoft Windows may not support HUP, for * example, whereas that is a widely use and supported signal under * Unix (and its variants); additionally, the JVM may be using some * signals (the use of -Xrs will reduce or disable them at the cost * of losing what the JVM wanted them for). * @exception IllegalArgumentException is thrown when the named * signal is not available for some reason. Watch out: the original * cause (missing class or method) may be wrapped inside the * exception! **/ public void handleSignal( final String signalName ) throws IllegalArgumentException { try { sun.misc.Signal.handle( new sun.misc.Signal(signalName), this ); } catch( IllegalArgumentException x ) { // Most likely this is a signal that's not supported on this // platform or with the JVM as it is currently configured throw x; } catch( Throwable x ) { // We may have a serious problem, including missing classes // or changed APIs throw new IllegalArgumentException( "Signal unsupported: "+signalName, x ); } } /** * Called by Sun Microsystems' signal trapping routines in the JVM. * @param signal The {@link sun.misc.Signal} that we received **/ public void handle( final sun.misc.Signal signal ) { // setChanged ensures that notifyObservers actually calls someone. // In simple cases this seems like extra work but in asynchronous // designs, setChanged might be called on one thread, and // notifyObservers, on another or only when multiple changes may // have been completed (to wrap up multiple changes in a single // notifcation). setChanged(); notifyObservers( signal ); } }