001         package com.croftsoft.core.net;
002    
003         import java.io.*;
004         import java.net.*;
005         import java.util.*;
006    
007    // Need to drop thread priority
008    
009         /*********************************************************************
010         * PortServer creates a java.net.ServerSocket which accepts connections
011         * and passes them on to com.orbs.net.SocketServer threads.
012         * 
013         * @version
014         *   $Id: PortServer.java,v 1.2 2008/09/20 04:12:46 croft Exp $
015         * @since
016         *   1997-04-19
017         * @author
018         *   <a href="https://www.croftsoft.com/">David Wallace Croft</a>
019         *********************************************************************/
020    
021         public final class  PortServer implements Runnable {
022         //////////////////////////////////////////////////////////////////////
023         //////////////////////////////////////////////////////////////////////
024    
025         private static final String  COPYRIGHT
026           = "PortServer (C) Copyright 1997 David Wallace Croft";
027    
028         private static final int  DEFAULT_PORT = 1234;
029    
030         private static final String  HELP
031           = "java com.orbs.net.PortServer <classname> <port> <filename>\n"
032           + "\n"
033           + "<classname> must designate a class that implements\n"
034           + "com.orbs.net.SocketServer.\n"
035           + "\n"
036           + "If <port> is not specified, the default value of\n"
037           + DEFAULT_PORT + " will be used.\n"
038           + "\n"
039           + "If <shutdown_semaphore_filename> is specified and the file\n"
040           + "does not exist, the program will not start.  If the file is\n"
041           + "deleted, shutdown will occur immediately after the next\n"
042           + "connection.\n";
043    
044         private Class         serverClass;
045         private int           port;
046         private File          semaphore;
047    
048         private boolean       shutdown = false;
049         private ServerSocket  serverSocket;
050         private Thread        thread;
051         private long          nextUniqueID = 0;
052    
053         private Vector        thread_Vector = new Vector ( );
054         private Vector        socket_Vector = new Vector ( );
055         private Vector        server_Vector = new Vector ( );
056    
057         //////////////////////////////////////////////////////////////////////
058         //////////////////////////////////////////////////////////////////////
059    
060         /*********************************************************************
061         *********************************************************************/
062         public static final void  main ( String [ ]  args ) {
063         //////////////////////////////////////////////////////////////////////
064           System.out.println ( COPYRIGHT );
065           try {
066             Class  serverClass = Class.forName ( args [ 0 ] );
067             int  port = DEFAULT_PORT;
068             if ( args.length > 1 ) port = Integer.parseInt ( args [ 1 ] );
069             File  semaphore = null;
070             if ( args.length > 2 ) semaphore = new File ( args [ 2 ] );
071             new PortServer ( serverClass, port, semaphore );
072           } catch ( Throwable  t ) {
073             t.printStackTrace ( );
074             System.out.println ( HELP );
075             System.out.println ( t.getMessage ( ) );
076             return;
077           }
078         }
079    
080         public  PortServer (
081           Class  serverClass, int  port, File  semaphore ) {
082         //////////////////////////////////////////////////////////////////////
083           boolean  found = false;
084           Class [ ]  interfaces = serverClass.getInterfaces ( );
085           for ( int  i = 0; i < interfaces.length; i++ ) {
086             if ( interfaces [ i ].getName ( ).equals (
087               "com.croftsoft.core.net.SocketServer" ) ) {
088               found = true;
089               break;
090             }
091           }
092           if ( !found ) {
093             throw new RuntimeException (
094               "Class that implements com.orbs.net.SocketServer required." );
095           }
096           if ( ( port < 0 ) || ( port > 65535 ) ) {
097             throw new RuntimeException (
098               "Port number must be between 0 and 65535 inclusive." );
099           }
100           if ( ( semaphore != null ) && !semaphore.exists ( ) ) {
101             throw new RuntimeException (
102               "Semaphore file must be exist upon startup." );
103           }
104    
105           this.serverClass = serverClass;
106           this.port        = port;
107           this.semaphore   = semaphore;
108    
109           ( thread = new Thread ( this ) ).start ( );
110         }
111    
112         public final void  run ( ) {
113         //////////////////////////////////////////////////////////////////////
114           try {
115             serverSocket = new ServerSocket ( port );
116             while ( !shutdown ) {
117               if ( ( semaphore != null ) && !semaphore.exists ( ) ) {
118                 throw new Exception ( "Semaphore file does not exist." );
119               }
120               synchronized ( thread_Vector ) {
121                 Enumeration  e = thread_Vector.elements ( );
122                 while ( e.hasMoreElements ( ) ) {
123                   Thread  serverThread = ( Thread ) e.nextElement ( );
124                   if ( !serverThread.isAlive ( ) ) {
125                     terminate ( serverThread );
126                   }
127                 }
128               }
129               Socket  socket = serverSocket.accept ( );
130               SocketServer  socketServer
131                 = ( SocketServer ) serverClass.newInstance ( );
132               socketServer.setPortServer ( this );
133               socketServer.setSocket ( socket );
134               socketServer.setUniqueID ( getNextUniqueID ( ) );
135               Thread  serverThread = new Thread ( socketServer );
136               add ( socketServer, serverThread, socket );
137               serverThread.start ( );
138             }
139           } catch ( Throwable  t ) { terminate ( t ); }
140         }
141    
142         private synchronized final void  add (
143           SocketServer  socketServer, Thread  serverThread, Socket  socket ) {
144         //////////////////////////////////////////////////////////////////////
145           server_Vector.addElement ( socketServer );
146           thread_Vector.addElement ( serverThread );
147           socket_Vector.addElement ( socket       );
148         }
149    
150         public synchronized final void  terminate ( Throwable  t ) {
151         //////////////////////////////////////////////////////////////////////
152           if ( shutdown ) return;
153           shutdown = true;
154           if ( t != null ) t.printStackTrace ( );
155           Enumeration  e = thread_Vector.elements ( );
156           while ( e.hasMoreElements ( ) ) {
157             terminate ( ( Thread ) e.nextElement ( ) );
158           }
159           try { serverSocket.close ( ); } catch ( Throwable  t1 ) { }
160           try { thread.stop ( ); } catch ( Throwable  t1 ) { }
161         }
162    
163         public synchronized final void  terminate (
164           SocketServer  socketServer ) {
165         //////////////////////////////////////////////////////////////////////
166           int  i = server_Vector.indexOf ( socketServer );
167           terminate ( i );
168         }
169    
170         private synchronized final void  terminate ( Thread  thread ) {
171         //////////////////////////////////////////////////////////////////////
172           int  i = thread_Vector.indexOf ( thread );
173           terminate ( i );
174         }
175    
176         private synchronized final void  terminate ( int  i ) {
177         //////////////////////////////////////////////////////////////////////
178           if ( i < 0 ) return;
179           try { ( ( Socket ) socket_Vector.elementAt ( i ) ).close ( ); }
180           catch ( Throwable  t1 ) { }
181           try { ( ( Thread ) thread_Vector.elementAt ( i ) ).stop ( ); }
182           catch ( Throwable  t2 ) { }
183           try {
184             server_Vector.removeElementAt ( i );
185             socket_Vector.removeElementAt ( i );
186             thread_Vector.removeElementAt ( i );
187           } catch ( Throwable  t ) {
188             t.printStackTrace ( );
189           }
190         }
191    
192         public final Vector  clone_server_Vector ( ) {
193         //////////////////////////////////////////////////////////////////////
194           return ( Vector ) server_Vector.clone ( );
195         }
196    
197         private final synchronized long  getNextUniqueID ( ) {
198         //////////////////////////////////////////////////////////////////////
199           return nextUniqueID++;
200         }
201    
202         //////////////////////////////////////////////////////////////////////
203         //////////////////////////////////////////////////////////////////////
204         }