Go to the documentation of this file.00001
00002 import java.io.BufferedReader;
00003 import java.io.IOException;
00004 import java.io.InputStreamReader;
00005 import java.io.OutputStreamWriter;
00006 import java.io.PrintWriter;
00007 import java.net.Socket;
00008 import java.net.UnknownHostException;
00009 import java.text.SimpleDateFormat;
00010 import java.util.Calendar;
00011
00012
00013
00014
00015
00016
00017 public class ChatClient extends Thread
00018 {
00019
00020
00021
00022 public interface Context
00023 {
00024
00025
00026
00027
00028
00029 public abstract void logMessage( String str );
00030
00031
00032
00033
00034
00035
00036 public abstract void logStatus( String str );
00037 }
00038
00039
00040
00041
00042
00043
00044 private String host;
00045
00046
00047
00048
00049 private int port;
00050
00051
00052
00053
00054 private PrintWriter out;
00055
00056
00057
00058
00059 private Socket socket;
00060
00061
00062
00063
00064 private volatile boolean running;
00065
00066
00067
00068
00069 private Context context;
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081 public ChatClient( String host, int port, Context context )
00082 {
00083 assert( context != null );
00084
00085 this.socket = null;
00086 this.host = host;
00087 this.port = port;
00088 this.context = context;
00089 this.out = null;
00090 this.running = false;
00091 }
00092
00093
00094
00095
00096 @Override
00097 public void start ()
00098 {
00099 if ( isAlive () || running ) {
00100 return;
00101 }
00102
00103 running = true;
00104 super.start ();
00105 }
00106
00107
00108
00109
00110
00111
00112 public void send( String message )
00113 {
00114 synchronized( this )
00115 {
00116 if ( out == null || message == null ) {
00117 return;
00118 }
00119
00120 out.println( message );
00121 out.flush ();
00122 }
00123 }
00124
00125
00126
00127
00128
00129
00130
00131 public void send( String message, String userId )
00132 {
00133 send( userId + " :: " + message );
00134 }
00135
00136
00137
00138
00139 public void close ()
00140 {
00141 synchronized( this )
00142 {
00143 running = false;
00144
00145 if ( socket != null && ! socket.isClosed () ) {
00146 try {
00147 socket.close ();
00148 } catch( IOException e ) {
00149
00150 }
00151 }
00152 }
00153 }
00154
00155
00156
00157
00158 private static String EscapeHTML( String str )
00159 {
00160 return str.replaceAll( "&", "&" )
00161 .replaceAll( "<", "<" )
00162 .replaceAll( ">", ">" )
00163 .replaceAll( "\"", """ );
00164 }
00165
00166
00167
00168
00169 private void reportError( String str )
00170 {
00171 context.logMessage(
00172 "<code>" + now ()
00173 + " <span style='color:red'>"
00174 + EscapeHTML( str )
00175 + "</span></code><br/>"
00176 );
00177 }
00178
00179
00180
00181
00182 private void reportInfo( String str )
00183 {
00184 context.logMessage(
00185 "<code>" + now ()
00186 + " <span style='color:green'>"
00187 + EscapeHTML( str )
00188 + "</span></code><br/>"
00189 );
00190 }
00191
00192
00193
00194
00195
00196
00197 private static String now ()
00198 {
00199 Calendar cal = Calendar.getInstance ();
00200 SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" );
00201 return sdf.format( cal.getTime() );
00202 }
00203
00204
00205
00206
00207
00208 @Override
00209 public void run ()
00210 {
00211 reportInfo( "Connecting to " + host + ":" + port + "..." );
00212 context.logStatus( "Connecting to " + host + ":" + port + "..." );
00213
00214
00215
00216
00217 try
00218 {
00219 synchronized( this ) {
00220 socket = new Socket( host, port );
00221 }
00222 }
00223 catch( UnknownHostException e )
00224 {
00225 reportError( "'Unknown host' exception while creating socket" );
00226 reportError( e.toString () );
00227 running = false;
00228 }
00229 catch( IOException e )
00230 {
00231 reportError( "I/O exception while connecting" );
00232 reportError( e.toString () );
00233 running = false;
00234 }
00235
00236
00237
00238
00239
00240 InputStreamReader reader = null;
00241 try
00242 {
00243 if ( socket != null ) {
00244 reader = new InputStreamReader( socket.getInputStream (), "utf-8" );
00245 }
00246 }
00247 catch( IOException e )
00248 {
00249 reportError( "I/O exception while getting input stream" );
00250 reportError( e.toString () );
00251 running = false;
00252 reader = null;
00253 }
00254
00255
00256
00257
00258 try
00259 {
00260 if ( socket != null ) {
00261 out = new PrintWriter(
00262 new OutputStreamWriter( socket.getOutputStream(), "utf-8" ),
00263 true );
00264 }
00265 }
00266 catch( IOException e )
00267 {
00268 reportError( "I/O exception while getting output stream" );
00269 reportError( e.toString () );
00270 running = false;
00271 out = null;
00272 }
00273
00274
00275
00276
00277 BufferedReader in = null;
00278 if ( running ) {
00279 context.logStatus( "Connected to " + host + ":" + port );
00280 reportInfo( "Connected; type a message, then press Enter or click 'Send'" );
00281 reportInfo( "All your messages will be prefixed with your ID..." );
00282 in = new BufferedReader( reader );
00283 }
00284
00285
00286
00287
00288 while( running )
00289 {
00290 try
00291 {
00292 String message = in.readLine ();
00293
00294
00295
00296
00297 String[] parts = message.split( ":: ", 2 );
00298 String userId = "[Anonymous]";
00299
00300 if ( message.startsWith( "WWHHOO: " ) ) {
00301 userId = "WWHHOO";
00302 message = message.substring( 8 );
00303 } else if ( parts.length == 0 ) {
00304 message = parts[0];
00305 } else if ( parts[0].trim().length () == 0 && parts.length >= 2 ) {
00306 message = parts[1];
00307 } else if ( parts.length >= 2 ) {
00308 userId = parts[0].trim ();
00309 message = parts[1];
00310 } else {
00311 message = parts[0];
00312 }
00313
00314 context.logMessage(
00315 "<code>" + now ()
00316 + " "
00317 + EscapeHTML( userId ).trim ()
00318 + ": <span style='"
00319 + ( userId.equals( "Eliza" ) ? "color:red" : "color:blue" )
00320 + "'>"
00321 + EscapeHTML( message ).trim ()
00322 + "</span></code><br/>"
00323 );
00324 }
00325 catch( IOException e )
00326 {
00327 reportError( "Connection lost!" );
00328 reportError( e.toString () );
00329 running = false;
00330 }
00331 }
00332
00333 reportInfo( "Closing connection " + host + ":" + port + "..." );
00334
00335
00336
00337
00338 try
00339 {
00340 if ( out != null ) {
00341 out.close ();
00342 }
00343 if ( in != null ) {
00344 in.close ();
00345 }
00346 synchronized( this )
00347 {
00348 if ( socket != null && ! socket.isClosed () ) {
00349 socket.close ();
00350 }
00351 }
00352 }
00353 catch( IOException e )
00354 {
00355 reportError( "I/O exception while closing connection" );
00356 reportError( e.toString () );
00357 }
00358
00359 reportInfo( "Thread " + host + ":" + port + " completed." );
00360 }
00361 }