1 // 2 package server; 3 import java.net.*; 4 import java.io.*; 5 import java.util.*; 6 import dx.protocol.*; 7 8 public abstract class DXThread extends Thread 9 { 10 protected Socket clientSocket = null; 11 protected Vector actions; 12 13 private BufferedReader is; 14 private PrintStream os; 15 private Vector msg_queue; 16 17 // 18 // Failure status 19 // 20 private boolean failed = false; setFailed()21 protected void setFailed() 22 { 23 failed = true; 24 } 25 isFailed()26 protected boolean isFailed() 27 { 28 return failed; 29 } 30 31 // 32 // debug status 33 // 34 private boolean debug = false; isDebug()35 protected boolean isDebug() 36 { 37 return debug; 38 } 39 cleanUp()40 public void cleanUp() 41 { } 42 43 DXThread( Socket client )44 protected DXThread ( Socket client ) 45 { 46 clientSocket = client; 47 48 try { 49 is = new BufferedReader( new InputStreamReader( clientSocket.getInputStream() ) ); 50 os = new PrintStream( clientSocket.getOutputStream(), false ); 51 } 52 53 catch ( Exception e ) { 54 e.printStackTrace(); 55 is = null; 56 os = null; 57 } 58 59 actions = new Vector( 20 ); 60 msg_queue = new Vector( 10 ); 61 62 String debug_option_string = getClass().getName() + ".debug"; 63 String dbgmsgs = System.getProperty( debug_option_string ); 64 65 if ( dbgmsgs != null ) debug = true; 66 else debug = false; 67 68 failed = false; 69 } 70 getNextString()71 protected String getNextString() throws IOException 72 { 73 String retval = null; 74 75 synchronized ( msg_queue ) { 76 if ( getQueueSize() > 0 ) { 77 String msg = ( String ) msg_queue.firstElement(); 78 msg_queue.removeElementAt( 0 ); 79 retval = msg; 80 } 81 82 else 83 retval = is.readLine(); 84 } 85 86 return retval; 87 } 88 getQueueSize()89 protected int getQueueSize() throws IOException 90 { 91 int qsize = 0; 92 93 synchronized ( msg_queue ) { 94 while ( is.ready() ) { 95 String inputLine = is.readLine(); 96 msg_queue.addElement( ( Object ) inputLine ); 97 } 98 99 qsize = msg_queue.size(); 100 } 101 102 return qsize; 103 } 104 run()105 public final void run() 106 { 107 String inputLine = null; 108 109 try { 110 while ( ( failed == false ) && ( ( inputLine = getNextString() ) != null ) ) { 111 if ( debug ) 112 System.out.println ( getName() + ": " + inputLine ); 113 114 Enumeration enum1 = actions.elements(); 115 116 boolean executed = false; 117 118 while ( enum1.hasMoreElements() ) { 119 DXThreadCommand stc = ( DXThreadCommand ) enum1.nextElement(); 120 121 if ( inputLine.startsWith( stc.getCommandString() ) ) { 122 executed = stc.execute( inputLine ); 123 124 if ( executed ) break; 125 } 126 } 127 128 if ( !executed ) 129 System.out.println ( getName() + ": Unrecognized: " + 130 inputLine ); 131 } 132 } 133 134 catch ( SocketException se ) {} 135 catch ( Exception e ) { 136 e.printStackTrace(); 137 setFailed(); 138 } 139 140 disconnect(); 141 } 142 transmit( threadMsg msg )143 protected void transmit( threadMsg msg ) 144 { 145 if ( isDebug() ) { 146 System.out.println ( " " + 147 getName() + ": " + msg.toString() ); 148 } 149 150 os.println ( msg.toString() ); 151 os.flush(); 152 } 153 154 // 155 // There's a problem here I don't understand. The thread is generally sitting 156 // in getNextString() waiting for input from the browser. If DXServer decides 157 // it's time to shutdown, then he wants to call disconnect() for every running 158 // thread. The problem with that is that the call to close a socket blocks. 159 // I don't know why - must have something to do with having a thread inside 160 // readLine. The book says these methods aren't synchronized but apparently 161 // something is synchronized inside there. So, I wrote virtual cleanUp() 162 // so that DXServer can call run clean-up type work before shutting down. 163 // That's important because we need a change to erase image files. 164 // disconnect( threadMsg msg )165 protected boolean disconnect( threadMsg msg ) 166 { 167 cleanUp(); 168 169 try { 170 clientSocket.close(); 171 } 172 173 catch ( Exception e ) { } 174 175 try { 176 is.close(); 177 } 178 179 catch ( Exception e ) { } 180 181 try { 182 os.close(); 183 } 184 185 catch ( Exception e ) { } 186 187 return true; 188 } 189 disconnect()190 protected boolean disconnect() 191 { 192 return disconnect( null ); 193 } 194 peekQueue( String cmd, boolean remove )195 protected String peekQueue( String cmd, boolean remove ) throws IOException 196 { 197 String retval = null; 198 199 synchronized ( msg_queue ) { 200 if ( getQueueSize() > 0 ) { 201 Enumeration enum1 = msg_queue.elements(); 202 203 while ( enum1.hasMoreElements() ) { 204 String msg = ( String ) enum1.nextElement(); 205 206 if ( msg.startsWith( cmd ) ) { 207 retval = msg; 208 break; 209 } 210 } 211 212 if ( remove ) 213 msg_queue.removeElement( retval ); 214 } 215 } 216 217 return retval; 218 } 219 220 221 } // end DXThread 222