ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/cms/source/conient/uk/org/iscream/cms/conient/ConnectionHandler.java
Revision: 1.23
Committed: Thu Mar 1 17:28:31 2001 UTC (23 years, 3 months ago) by ajm
Branch: MAIN
Changes since 1.22: +6 -4 lines
Log Message:
now detects server protocol version correctly

File Contents

# User Rev Content
1 ajm 1.6 //---PACKAGE DECLARATION---
2 ajm 1.10 package uk.ac.ukc.iscream.conient;
3 ajm 1.6
4     //---IMPORTS---
5 ajm 1.1 import uk.ac.ukc.iscream.util.*;
6 ajm 1.2 import java.io.*;
7 ajm 1.1 import java.net.*;
8 ajm 1.2 import javax.swing.JOptionPane;
9 ajm 1.1
10 ajm 1.6 /**
11     * This is the main thread for the client.
12     * Once started i continually checks it actionQueue
13     * for actions that other areas of the system have placed
14     * there, it then performs those actions.
15     *
16     * Currently this is the main thread where all non-GUI events
17     * are dispatched to.
18     *
19 ajm 1.11 * @author $Author: ajm4 $
20 ajm 1.23 * @version $Id: ConnectionHandler.java,v 1.22 2001/03/01 02:29:44 ajm4 Exp $
21 ajm 1.6 */
22 ajm 1.1 public class ConnectionHandler extends Thread {
23 ajm 1.2
24 ajm 1.6 //---FINAL ATTRIBUTES---
25    
26     /**
27     * The current CVS revision of this class
28     */
29 ajm 1.23 public final String REVISION = "$Revision: 1.22 $";
30 ajm 1.6
31 tdb 1.7
32     /**
33     * The hardcoded protocol version that we are using.
34     * Used when handshaking with the server
35     */
36 ajm 1.20 public final double PROTOCOL_VERSION = 1.1;
37 ajm 1.2
38 tdb 1.7 /**
39     * Thread action DONOTHING.
40     * This is an invalid action, but here for completeness
41     * if anything sends this action it will warn appropriately
42     * but do what it says, ie, nothing ;)
43     */
44 ajm 1.1 public static final int DONOTHING = 0;
45 tdb 1.7
46     /**
47     * Thread action CONNECT.
48     * Opens the control link to the i-scream server.
49     */
50 ajm 1.1 public static final int CONNECT = 1;
51 tdb 1.7
52     /**
53     * Thread action STARTDATA.
54     * Opens the data link to the i-scream server
55     * and prepares all gui data components for data
56     * it then starts all relavant threads going.
57     */
58 ajm 1.2 public static final int STARTDATA = 2;
59 tdb 1.7
60     /**
61     * Thread action STOPDATA.
62     * Closes the data link and shuts down all components
63     * that update gui for various things.
64     */
65 ajm 1.2 public static final int STOPDATA = 3;
66 tdb 1.7
67     /**
68     * Thread action DISCONNECT.
69     * Checks to see if STOPDATA has been called if not,
70     * it will add STOPDATA and then DISCONNECT to
71     * the action queue and return. If STOPDATA has been
72     * called it closes down the Control Link and tidies up
73     * all relevant threads
74     */
75 ajm 1.2 public static final int DISCONNECT = 4;
76 tdb 1.7
77     /**
78     * Thread action QUIT.
79     * Checks the status of the two links, if either
80     * are still up, it queues the appropriate commands
81     * to close them down. It then System.exit(0)'s!
82     */
83 ajm 1.4 public static final int QUIT = 5;
84 ajm 1.6
85 ajm 1.12 /**
86 ajm 1.14 * Thread action GETCONFIGURATION
87     * Starts the command to obtain the configuration
88     * from the server.
89     * It then passes the IO to the Configuration object
90     * so it can obtain any specific configuration
91     */
92     public static final int GETCONFIGURATION = 6;
93    
94     /**
95 ajm 1.12 * This is the time in seconds that this class
96     * should wait on the DataReader class to fully
97     * shutdown after calling shutdown() before
98     * forcing a shutdown
99     */
100     public static final int DATAREADER_SHUTDOWN_TIMEOUT = 5;
101    
102 ajm 1.13 /**
103     * The default local server to connect to when a
104     * firewall is in use if one is not specified in the server
105     */
106     public static final String DEFAULT_FIREWALL_SERVER = "localhost";
107    
108     /**
109     * The default time in seconds to wait for the
110     * firewall setup command to execute
111     */
112     public static final int DEFAULT_FIREWALL_COMMANDWAIT = 5;
113    
114 ajm 1.6 //---STATIC METHODS---
115    
116     //---CONSTRUCTORS---
117    
118 tdb 1.7 /**
119     * Constructs new data handler.
120     * Needs a reference to the data panel so that
121     * it can set it processing inBound data
122     * Also gets a reference to the queue that will be
123     * used by other areas of the system to send it actions
124     *
125     * @param data the DataPanel in use
126     * @param actionQueue the actionQueue for this class
127     */
128 ajm 1.1 public ConnectionHandler(DataPanel data, Queue actionQueue) {
129     _data = data;
130     _actionQueue = actionQueue;
131     _myQueue = _actionQueue.getQueue();
132     }
133    
134 ajm 1.6 //---PUBLIC METHODS---
135    
136 tdb 1.7
137     /**
138     * Starts this ConnectionHandler running.
139     * This basically runs until told to stop, it gets "actions"
140     * from its actionQueue and switch's on them do determine
141     * what it should do it then carries out the action
142     *
143     * For details on what each action does see the action
144     * types.
145     */
146 ajm 1.1 public void run() {
147 ajm 1.20 if(_configuration.getProperty("control.onstartconnect").equals("1")) {
148 ajm 1.13 _actionQueue.add(new Integer(CONNECT));
149     }
150 ajm 1.20 if(_configuration.getProperty("data.onstartconnect").equals("1")) {
151 ajm 1.13 _actionQueue.add(new Integer(STARTDATA));
152     }
153 tdb 1.7 while(_running) {
154 ajm 1.1 // we wait for a call...
155     int action = 0;
156     try {
157     action = ((Integer) _actionQueue.get(_myQueue)).intValue();
158     } catch (InvalidQueueException e) {
159 ajm 1.12 // we 're never going to get this
160     // but if we do we should do something nasty
161     throw new RuntimeException("unable to retrieve events from actionQueue!");
162 ajm 1.1 }
163    
164     // examine our action...
165     // if it was to connect...then we connect...
166 ajm 1.2 switch(action) {
167     case CONNECT:
168 ajm 1.12 if (_controlLink == null) {
169 ajm 1.13 try {
170     // get the server name from the config
171     _configuredServer = _configuration.getProperty("control.server");
172    
173     if (_configuredServer == null) {
174     throw new IOException("no i-scream server in current configuration");
175     }
176    
177     // open the socket to the server and bind the IO
178     // get the port from the config
179     String portString = _configuration.getProperty("control.port");
180     if (portString == null) {
181     throw new IOException("no i-scream server port in current configuration");
182     }
183     int port = 0;
184 ajm 1.12 try {
185 ajm 1.13 port = Integer.parseInt(portString);
186     } catch (NumberFormatException e) {
187     throw new IOException("no valid i-scream server port in current configuration");
188     }
189    
190     // start firewall if needed
191     _server = handleFirewall(_configuredServer, port, _controlFirewallProcess);
192    
193     Conient.setControlStatus("Connecting to - " + _server);
194     _controlLink = new Socket(_server, port);
195     _inBound = new BufferedReader(new InputStreamReader(_controlLink.getInputStream()));
196     _outBound = new PrintWriter(_controlLink.getOutputStream());
197     Conient.setControlStatus("Connection Established - " + _server);
198    
199     String response;
200     response = _inBound.readLine();
201    
202     // check the servers Protocol Identity against our own
203     // we SHOULD be backwards compatible, so we can continue if
204     // they are using a newer protocol, anything else then we die
205 ajm 1.23 double serverProtocolVersion = Double.parseDouble(response.substring(9, response.length()));
206     Conient.addMessage("Protocol Versions: server [" + serverProtocolVersion + "] client [" + PROTOCOL_VERSION + "]");
207     if (serverProtocolVersion > PROTOCOL_VERSION) {
208 ajm 1.13 Conient.addMessage("WARNING{control link}: server is using a newer protocol (" + response + "), please update your client, continuing with old protocol (PROTOCOL " + PROTOCOL_VERSION + ")" );
209 ajm 1.23 } else if (serverProtocolVersion < PROTOCOL_VERSION) {
210 ajm 1.13 // tidy up
211     throw new IOException("incompatible protocol version");
212     }
213    
214     // send the name of the client
215     _outBound.println(_configuration.getProperty("clientname"));
216     _outBound.flush();
217     response = _inBound.readLine();
218     if (!response.equals("OK")) {
219     // tidy up
220 ajm 1.12
221 ajm 1.13 throw new IOException("client name rejected - " + _configuration.getProperty("clientname"));
222     }
223 ajm 1.14 // get the config...we are connected now!
224 ajm 1.18 getConfigFromServer();
225 ajm 1.22
226 ajm 1.13 } catch (IOException e) {
227     // print the error and tidy up what's left
228     Conient.addMessage("ERROR{control link}: " + e);
229     _controlLink = null;
230     // and the firewall handler if there is one
231 ajm 1.16 closeFirewall(_controlFirewallProcess);
232 ajm 1.13 _actionQueue.clearQueue(_myQueue);
233     Conient.setControlStatus("Disconnected");
234 ajm 1.2 }
235 ajm 1.12 } else {
236     Conient.addMessage("WARNING{control link}: already established");
237 ajm 1.2 }
238     break;
239     case STARTDATA:
240 ajm 1.12 // as long as the data link hasn't been established
241     // we want to establish it
242     if (_dataLink == null) {
243     // check that the control link is open, if it isn't we
244     // might want to sort that problemo out
245     // we do this by simply queueing the event to occour, then
246     // this event to run again ;-)
247 tdb 1.7 if(_controlLink == null) {
248 ajm 1.12 Conient.addMessage("WARNING{data link}: control link not established - queueing start events");
249 tdb 1.7 _actionQueue.add(new Integer(CONNECT));
250     _actionQueue.add(new Integer(STARTDATA));
251 ajm 1.12 } else {
252     try {
253 ajm 1.22 // set our host list if we know we have one we need to set
254     String hostList = _configuration.getProperty("hostList");
255     boolean hostListSet = false;
256     // send our hostList if we have
257     if (_configuration.getProperty("useHostList").equals("1")) {
258     if (hostList.equals("")) {
259     Conient.addMessage("WARNING{control link}: your host list is empty, the server will send ALL hosts");
260     }
261     hostListSet = setHostList(hostList);
262     // if not, indicate we want the lot
263     } else {
264     hostListSet = setHostList("");
265     }
266     // warn if there was a problem, it will have already error'd
267     if (!hostListSet) {
268     Conient.addMessage("WARNING{control link}: unable to set host list");
269     }
270 ajm 1.12 // ask the server to start the data link
271     String response;
272     _outBound.println("STARTDATA");
273     _outBound.flush();
274     response = _inBound.readLine();
275    
276     // see if the server suggested a good port
277     if (response.equals("ERROR")) {
278     throw new IOException("server unable to start data link at this time");
279     }
280 ajm 1.13 int port = 0;
281 ajm 1.12 try {
282 ajm 1.13 port = Integer.parseInt(response);
283 ajm 1.12 } catch (NumberFormatException e) {
284     throw new IOException("invalid data port suggested by server - " + response);
285     }
286    
287 ajm 1.13 // start firewall if needed
288     _server = handleFirewall(_configuredServer, port, _dataFirewallProcess);
289     Conient.setDataStatus("Connecting to - " + _server + ":" + response);
290    
291     _dataLink = new Socket(_server, port);
292    
293 ajm 1.12 response = _inBound.readLine();
294     if (!response.equals("OK")) {
295     throw new IOException("server reported error establishing data channel");
296     }
297    
298     // if the socket was ok, then we attack our IO hooks
299     _dataInBound = new BufferedReader(new InputStreamReader(_dataLink.getInputStream()));
300     _dataOutBound = new PrintWriter(_dataLink.getOutputStream());
301     Conient.setDataStatus("Connection Established - " + _server);
302 ajm 1.15 // now we want to start reading the data in
303     // so we start the appropriate components on their way
304     // we create a queue to give to both the reader and the
305     // displayer
306     Queue theQueue = new Queue();
307     _dataReader = new DataReader(_dataInBound, theQueue);
308     _data.setQueue(theQueue);
309     _data.cleanUpTabs();
310    
311     // start the data rocking
312     new Thread(_data).start();
313     _dataReader.start();
314     // finished for us....
315 ajm 1.12 } catch (IOException e) {
316     // print the error and tidy up what's left
317     Conient.addMessage("ERROR{data link}: " + e);
318     _dataLink = null;
319 ajm 1.16 // and the firewall handler if there is one
320     closeFirewall(_dataFirewallProcess);
321 ajm 1.13 _actionQueue.clearQueue(_myQueue);
322 ajm 1.12 Conient.setDataStatus("Disconnected");
323     }
324 ajm 1.2 }
325 ajm 1.12 } else {
326     Conient.addMessage("WARNING{data link}: already established");
327 ajm 1.2 }
328     break;
329     case STOPDATA:
330 ajm 1.12 if(_dataLink != null) {
331     try {
332     String response;
333     // shut down the data link
334     Conient.setDataStatus("Disconnecting - " + _server);
335    
336     // close the reader
337     _dataReader.shutdown();
338     // wait for it to close
339     boolean dirtyShutdown = true;
340     long startTime = System.currentTimeMillis();
341     while((System.currentTimeMillis() - startTime) < (DATAREADER_SHUTDOWN_TIMEOUT * 1000)) {
342     if (!_dataReader.isAlive()) {
343     dirtyShutdown = false;
344     break;
345     }
346     }
347     // warn if it didn't shutdown in time
348     if (dirtyShutdown) {
349     Conient.addMessage("WARNING{data link}: data reader thread did not close within timeout, killing its IO anyway!");
350     }
351    
352     // tell the server
353     _outBound.println("STOPDATA");
354     _outBound.flush();
355     response = _inBound.readLine();
356    
357     // check the server was ok with our request...
358     // even if it wasn't we will go anyway!
359     if (!response.equals("OK")) {
360     throw new IOException("server didn't OK request to stop data channel - stopping anyway");
361     }
362    
363    
364     // close the lot down
365     _dataInBound.close();
366     _dataOutBound.close();
367     _dataLink.close();
368     // get rid of the socket
369     _dataLink = null;
370 ajm 1.13
371     // and the firewall handler if there is one
372 ajm 1.16 closeFirewall(_dataFirewallProcess);
373 ajm 1.13
374 ajm 1.12 Conient.setDataStatus("Disconnected");
375     } catch (IOException e) {
376     // print the error and tidy up what's left
377     Conient.addMessage("ERROR{data link}: " + e);
378     try {
379     _dataOutBound.close();
380     _dataInBound.close();
381     _dataLink.close();
382 ajm 1.13 // and the firewall handler if there is one
383 ajm 1.16 closeFirewall(_dataFirewallProcess);
384 ajm 1.12 } catch (IOException e2) {
385     Conient.addMessage("CRITICAL{control link}: unable to close socket - " + e2);
386     }
387     _dataLink = null;
388 ajm 1.13 _actionQueue.clearQueue(_myQueue);
389 ajm 1.12 Conient.setDataStatus("Disconnected");
390 ajm 1.2 }
391 ajm 1.12 } else {
392     Conient.addMessage("WARNING{data link}: already disconnected");
393 ajm 1.2 }
394     break;
395     case DISCONNECT:
396 ajm 1.12 if (_controlLink != null) {
397 ajm 1.2 if (_dataLink != null) {
398 ajm 1.12 // we want to tell ourselves to stop it
399     Conient.addMessage("WARNING{control link}: data link not disconnected - queueing stop events");
400     _actionQueue.add(new Integer(STOPDATA));
401     _actionQueue.add(new Integer(DISCONNECT));
402     } else {
403     try {
404     // request the server to disconnect
405     String response;
406     _outBound.println("DISCONNECT");
407     _outBound.flush();
408     response = _inBound.readLine();
409    
410     // check the server was ok with our request...
411     // even if it wasn't we will go anyway!
412     if (!response.equals("OK")) {
413     throw new IOException("server didn't OK request to stop control channel - stopping anyway");
414     }
415    
416     // then lets shutdown the link
417     Conient.setControlStatus("Disconnecting - " + _server);
418     _inBound.close();
419     _outBound.close();
420     _controlLink.close();
421     // for good measure
422     _controlLink = null;
423 ajm 1.13
424     // and the firewall handler if there is one
425 ajm 1.16 closeFirewall(_controlFirewallProcess);
426 ajm 1.13
427 ajm 1.12 Conient.setControlStatus("Disconnected");
428     } catch (IOException e) {
429 ajm 1.14 Conient.addMessage("ERROR{control link}: " + e);
430 ajm 1.12 try {
431     _inBound.close();
432     _outBound.close();
433     _controlLink.close();
434 ajm 1.13 // and the firewall handler if there is one
435 ajm 1.16 closeFirewall(_controlFirewallProcess);
436 ajm 1.12 } catch (IOException e2) {
437     Conient.addMessage("CRITICAL{control link}: unable to close socket - " + e2);
438     }
439     _controlLink = null;
440 ajm 1.13 _actionQueue.clearQueue(_myQueue);
441 ajm 1.12 Conient.setControlStatus("Disconnected");
442     }
443 ajm 1.2 }
444 ajm 1.12 } else {
445     Conient.addMessage("WARNING{control link}: already disconnected");
446 ajm 1.1 }
447 ajm 1.2 break;
448 ajm 1.4 case QUIT:
449 ajm 1.12 Conient.addMessage("Exiting.");
450 ajm 1.5 try {
451     // stop data and control if data up
452     if (_dataLink != null) {
453     _actionQueue.add(new Integer(STOPDATA));
454     _actionQueue.add(new Integer(DISCONNECT));
455     _actionQueue.add(new Integer(QUIT));
456     throw new IOException();
457     }
458     // stop control
459     if (_controlLink != null) {
460     _actionQueue.add(new Integer(DISCONNECT));
461     _actionQueue.add(new Integer(QUIT));
462     throw new IOException();
463     }
464 ajm 1.11 Conient.addMessage("Finished.");
465 ajm 1.5 // go!
466     System.exit(0);
467     } catch (IOException e) {
468 ajm 1.12 Conient.addMessage("WARNING: open connections detected - queueing stop events");
469 ajm 1.4 }
470     break;
471 ajm 1.14 case GETCONFIGURATION:
472 ajm 1.18 getConfigFromServer();
473 ajm 1.14 break;
474 ajm 1.1 }
475     }
476     }
477    
478 ajm 1.12 /**
479     * This method allows other classes
480     * to shutdown this connection handler.
481     */
482     public void shutdown() {
483     _running = false;
484     }
485    
486 ajm 1.6 //---PRIVATE METHODS---
487 ajm 1.18
488     /**
489 ajm 1.20 * This method performs the SETHOSTLIST command.
490     * This is run by the CONNECT command.
491     * It tells the server which hosts we are interested
492     * in, if "" is sent, this indicates we want ALL hosts.
493     *
494     * @param hostList the list of hosts as gained from the config
495     * @return if we succeeded in setting the host list
496     */
497     private boolean setHostList(String hostList) {
498     boolean success = false;
499     // must have a control link open
500     if (_controlLink != null) {
501     // data link must be closed (according to 1.1 PROTOCOL)
502     if(_dataLink == null) {
503     try {
504 ajm 1.21 Conient.addMessage("Setting host list to:" + hostList);
505 ajm 1.20 String response = null;
506     _outBound.println("SETHOSTLIST");
507     _outBound.flush();
508     response = _inBound.readLine();
509     if (!response.equals("OK")) {
510     throw new IOException("server refused - data link possibly still open?");
511     }
512     _outBound.println(hostList);
513     _outBound.flush();
514     response = _inBound.readLine();
515     if (!response.equals("OK")) {
516     throw new IOException("server had trouble with our request");
517     }
518     success = true;
519     } catch (IOException e) {
520     Conient.addMessage("ERROR{control link}: when setting hostlist - " + e);
521     }
522     }
523     }
524     return success;
525     }
526    
527    
528     /**
529 ajm 1.18 * This method performs the STARTCONFIG command on
530     * the server. this method is called after a CONNECT,
531     * and when a GETCONFIGURATION command is called.
532     */
533     private void getConfigFromServer() {
534     if(_controlLink != null) {
535     try {
536 ajm 1.21 Conient.addMessage("Getting configuration from server");
537 ajm 1.18 String response = null;
538     _outBound.println("STARTCONFIG");
539     _outBound.flush();
540     response = _inBound.readLine();
541     if (!response.equals("OK")) {
542     throw new IOException("server refused (" + response + ")");
543     }
544     _configuration.readServerConfiguration(_inBound, _outBound);
545     _outBound.println("ENDCONFIG");
546     _outBound.flush();
547     response = _inBound.readLine();
548     if (!response.equals("OK")) {
549     throw new IOException("server reported error when finishing configuration");
550     }
551     } catch (IOException e) {
552     Conient.addMessage("ERROR{control link}: when getting configuration - " + e);
553     }
554     }
555     }
556 ajm 1.6
557 ajm 1.13 /**
558     * Handles opening pipes through firewalls.
559     * It checks the configuration for various entries
560     * to set up the link or not.
561     *
562     * If a link is setup it will return the name of the
563     * new server to connect to, if a link is NOT setup,
564     * it will simply return the original server name.
565     *
566     * The name of the machine that the pipe is setup on
567     * defaults to "localhost", unless the configuration
568     * specifies otherwise.
569     *
570     * Once it has run the firewall command it then waits
571     * a set period according to the config for the firewall
572     * pipe to be set up.
573     *
574     * The firewall process should be destroyed when the
575     * link is finished with.
576     *
577     * @param server the name of the server to open up the pipe to
578     * @param port the port number to open up the pipe to
579     * @param firewallProcess the holder for the new firewall process
580     * @return the server to connect to, as determined by this routine
581     */
582     private String handleFirewall(String server, int port, Process firewallProcess) {
583     String firewallCommand = _configuration.getProperty("firewall.command");
584 ajm 1.19 String useFirewall = _configuration.getProperty("useFirewall");
585 ajm 1.13 String firewallCommandWait = _configuration.getProperty("firewall.commandwait");
586     String firewallServer = _configuration.getProperty("firewall.server");
587     // if we are running firewall support...then lets start it
588 ajm 1.20 if (useFirewall.equals("1")) {
589 ajm 1.13 // clean up the command with what we want
590     firewallCommand = replaceText(firewallCommand, "%PORT%", new Integer(port).toString());
591     firewallCommand = replaceText(firewallCommand, "%SERVER%", server);
592     Conient.addMessage("WARNING{firewall}: firewall pipes requested, running pipe setup command \"" + firewallCommand + "\"");
593     try {
594     // run the command
595     firewallProcess = Runtime.getRuntime().exec(firewallCommand);
596    
597     // work out how long we should wait before carrying on
598     int time = 0;
599     try {
600     time = Integer.parseInt(firewallCommandWait);
601     } catch (NumberFormatException e) {
602     time = 0;
603     }
604     if (time == 0) {
605     time = DEFAULT_FIREWALL_COMMANDWAIT;
606     }
607     Conient.addMessage("WARNING{firewall}: waiting " + time + " seconds for command to complete!");
608     // wait for the command to finish
609     try {
610     Thread.sleep(time * 1000);
611     } catch (InterruptedException e) {
612     }
613    
614     // set the server we want to return
615     server = firewallServer;
616 ajm 1.19 if (server.equals("")) {
617 ajm 1.13 server = DEFAULT_FIREWALL_SERVER;
618     }
619     } catch (IOException e) {
620     Conient.addMessage("ERROR{firewall}: unable to start pipe to i-scream server");
621     }
622     }
623     return server;
624 ajm 1.16 }
625    
626     /**
627     * Checks to see if the given firewall process
628     * has been created. If it has it calls destroy()
629     * on it.
630     *
631     * @param firewallProcess the process to check
632     */
633     private void closeFirewall(Process firewallProcess) {
634     if (firewallProcess != null) {
635 ajm 1.17 firewallProcess.destroy();
636     firewallProcess = null;
637 ajm 1.16 Conient.addMessage("WARNING{firewall}: firewall process destroyed");
638     }
639 ajm 1.13 }
640    
641     /**
642     * Searches a string and replaces all occurences
643     * of the given search text with the given replacement
644     * text.
645     *
646     * @param text the text to search and replace in
647     * @param search the string to look for and replace
648     * @param replace the text to replace with
649     * @return the updated version of text
650     */
651     private String replaceText(String text, String search, String replace) {
652     StringBuffer textBuffer = new StringBuffer(text);
653     int currIndex = 0;
654     currIndex = text.indexOf(search, currIndex);
655     while(currIndex != -1) {
656     if (currIndex != -1) {
657     textBuffer.delete(currIndex, currIndex + search.length());
658     textBuffer.insert(currIndex, replace);
659     }
660     text = textBuffer.toString();
661     currIndex = text.indexOf(search, currIndex + search.length());
662     }
663     return new String(textBuffer);
664     }
665 ajm 1.6 //---ACCESSOR/MUTATOR METHODS---
666    
667     //---ATTRIBUTES---
668    
669 ajm 1.12 /**
670     * The state if this thread
671     */
672 ajm 1.13 private boolean _running = true;
673 ajm 1.12
674     /**
675     * A reference to the displaying class DataPanel
676     */
677 ajm 1.13 private DataPanel _data;
678 ajm 1.12
679     /**
680     * The queue that actions are added to by other parts of the system
681     */
682 ajm 1.13 private Queue _actionQueue;
683 ajm 1.12
684     /**
685     * The queue number that we are reading from on the action queue
686     */
687 ajm 1.13 private int _myQueue;
688 ajm 1.12
689     /**
690     * The control link socket
691     */
692 ajm 1.13 private Socket _controlLink;
693 ajm 1.12
694     /**
695     * The data link socket
696     */
697 ajm 1.13 private Socket _dataLink;
698 ajm 1.12
699     /**
700     * The input for the control link
701     */
702 ajm 1.13 private BufferedReader _inBound;
703 ajm 1.12
704     /**
705     * The output for the control link
706     */
707 ajm 1.13 private PrintWriter _outBound;
708 ajm 1.12
709     /**
710     * The input for the data link
711     */
712 ajm 1.13 private BufferedReader _dataInBound;
713 ajm 1.12
714     /**
715     * The output for the data link
716     */
717 ajm 1.13 private PrintWriter _dataOutBound;
718 ajm 1.12
719     /**
720     * A reference to the DataReader in use
721     */
722 ajm 1.13 private DataReader _dataReader;
723    
724     /**
725     * A reference to the system configuration component
726     */
727     private Configuration _configuration = Configuration.getInstance();
728    
729     /**
730     * The server we will be connecting to
731     */
732     private String _server = null;
733 ajm 1.12
734     /**
735 ajm 1.13 * The server that the config says we should connect to
736 ajm 1.12 */
737 ajm 1.13 private String _configuredServer = null;
738 ajm 1.6
739 ajm 1.13 /**
740     * The process used to start the firewall pipe
741     * for the control link.
742     */
743     private Process _controlFirewallProcess = null;
744    
745     /**
746     * The process used to start the firewall pipe
747     * for the data link.
748     */
749     private Process _dataFirewallProcess = null;
750    
751 ajm 1.6 //---STATIC ATTRIBUTES---
752    
753 ajm 1.1 }