// Copyright © 2001-2002 // iWay Technology Company // Boulder, Colorado USA // http://www.iwaytechnology.com // // A limited right to copy this page for individual // (non-commercial) educational use only is hereby // granted. // // IWAY PUBLISHING COMPANY MAKES NO REPRESENTATIONS OR // WARRANTIES ABOUT THE SUITABILITY OF THIS SOFTWARE, // EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED // TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS // FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. IWAY // PUBLISHING COMPANY SHALL NOT BE LIABLE FOR ANY // DAMAGES SUFFERED AS A RESULT OF USING, MODIFYING OR // OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. // package iwaypublishing.util; import java.net.*; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; /********************************************************************** * IMsgPortManager extends Thread and, thus, is not created * on a Thread object externally instantiated by its creator. * This simplifies usage since a separate Thread instantiation * is not required to use the object. *
* IMsgPortManager uses the following 'protocol' convention: * Byte 0 sent to its port MUST be the 7-bit ascii code for * ':' (aka colon) and byte 1 MUST be the 7-bit ascii code for * 'X' - set terminate flag. Other combinations may be added. *
* Usage
* Listening Application:
* Initialization:
* IMsgPortManager man_ =
* new iwaypublishing.util.IMsgPortManager( portNum );
* man_.start();
*
* Within some loop (every 1-10 seconds for responsiveness):
* if( man_.isTerminate() ) {
* // Do Cleanup
* ...
* // Shutdown server thread
* man_.kill();
* man_.join();
* // exit or return (exiting)
* } else {
* // Continue working
* }
*
* Terminating App (separate JVM):
* if( IMsgPortManager.sendTerminate( portNum ) )
* {
* // Success
* } else {
* // Failure
* }
*/
public class IMsgPortManager extends Thread
{
private java.net.ServerSocket server_ = null;
private boolean terminate_ = false;
public static final byte[] terminateSequence = { (byte)':', (byte)'X' };
/*******************************************************************
* @param port int the port on which to listen.
*/
public IMsgPortManager( int port )
throws IOException,
SocketException
{
// Set up server on port defined by ctor call
server_ = new java.net.ServerSocket( port );
server_.setSoTimeout( 0 );
}
/******************************************************************/
public void kill()
throws IOException
{
// A ServerSocket.accept() call will cause this thread
// to be impervious to thread interrupts. So, as per
// Doug Lea "Concurrent Programming in Java", p172,
// close the socket to force termination - see run() -
// by causing an IOException to be thrown.
server_.close();
}
/******************************************************************/
public boolean isTerminate()
{
return terminate_;
}
/******************************************************************/
public void run()
{
boolean carryOn = true;
while( carryOn )
{
try{
// Blocks until client request, then creates new
// socket on which to conduct client conversation.
java.net.Socket client = server_.accept();
client.setSoTimeout( 0 );
java.io.InputStream in = client.getInputStream();
byte[] inbuf = new byte[32];
// Read designated port. In the case of
// Terminate, return.
in.read( inbuf, 0, 2 );
if( inbuf[0] == terminateSequence[0] &&
inbuf[1] == terminateSequence[1] )
{
terminate_ = true;
// Clean up client socket
in.close();
client.close();
return;
}
}
catch( SocketException e1 ) {
System.out.println( "SocketException in IMsgPortManager.run() - <" + e1.toString() + ">" );
carryOn = false;
}
catch( IOException e2 ) {
System.out.println( "IOException in IMsgPortManager.run() - " + e2.toString() );
carryOn = false;
}
}
}
/*******************************************************************
* Attempt to send a stop message to an instance of IMsgPortManager
* over the provided port number.
*
* @param int port number upon which to attempt communication.
* @return boolean true if connection to running app succeeded
* and terminate message was sent.
*/
public static boolean sendTerminate( int port )
{
boolean result = true;
try {
// Connect to running server through designated port
// (both this and first instance using same port)
Socket socket = new Socket( "localhost", port );
OutputStream out = socket.getOutputStream();
// Send predetermined "Stop" message
out.write( IMsgPortManager.terminateSequence );
out.flush();
out.close();
socket.close();
}
catch( Exception e ){ result = false; }
return result;
}
}