ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/cms/source/server/uk/org/iscream/cms/server/clientinterface/TCPControlHandler.java
Revision: 1.17
Committed: Tue Feb 27 01:10:01 2001 UTC (23 years, 3 months ago) by tdb
Branch: MAIN
Changes since 1.16: +6 -6 lines
Log Message:
Moved the last catchall to close the DataHandlers. Now we'll be sure to close
any that are left open when we close the Thread.

File Contents

# User Rev Content
1 tdb 1.1 //---PACKAGE DECLARATION---
2     package uk.ac.ukc.iscream.clientinterface;
3    
4     //---IMPORTS---
5     import uk.ac.ukc.iscream.util.*;
6     import uk.ac.ukc.iscream.componentmanager.*;
7     import uk.ac.ukc.iscream.core.*;
8     import java.net.Socket;
9     import java.net.ServerSocket;
10     import java.io.InputStream;
11     import java.io.OutputStream;
12     import java.io.IOException;
13     import java.io.BufferedReader;
14     import java.io.PrintWriter;
15     import java.io.InputStreamReader;
16    
17    
18     /**
19     * Acts as a Control Handler to a TCP based client.
20     *
21 tdb 1.2 * @author $Author: tdb1 $
22 tdb 1.17 * @version $Id: TCPControlHandler.java,v 1.16 2001/02/26 00:58:25 tdb1 Exp $
23 tdb 1.1 */
24     class TCPControlHandler extends Thread {
25    
26     //---FINAL ATTRIBUTES---
27    
28     /**
29     * The current CVS revision of this class
30     */
31 tdb 1.17 public final String REVISION = "$Revision: 1.16 $";
32 tdb 1.1
33 tdb 1.9 /**
34     * This is our protocol version. It is hardcoded to ensure
35     * that it doesn't get accidently changed. A change to the
36     * protocol would also require changing this classes code !
37     */
38 tdb 1.4 public static final String PROTOVER = "PROTOCOL 1.1";
39 tdb 1.1
40     //---STATIC METHODS---
41    
42     //---CONSTRUCTORS---
43 tdb 1.9
44     /**
45     * Construct a new TCPControlHandler, and setup the reader
46     * and writer for the new Socket.
47     *
48     * @param socket The Socket connected to the new Client
49     * @param packetSorter A reference to the PacketSorter in the component
50 tdb 1.15 * @param queueMonitorInterval The interval at which to monitor our Queue
51 tdb 1.9 */
52 tdb 1.15 public TCPControlHandler(Socket socket, PacketSorter packetSorter, int queueMonitorInterval) throws IOException {
53 tdb 1.1 _socket = socket;
54 tdb 1.9 _packetSorter = packetSorter;
55 tdb 1.15 _queueMonitorInterval = queueMonitorInterval;
56 tdb 1.9 // setup the reader & writer
57 tdb 1.1 _socketIn = new BufferedReader(new InputStreamReader(_socket.getInputStream()));
58 tdb 1.13 _socketOut = new PrintWriter(_socket.getOutputStream(), true);
59 tdb 1.9 // set the default hostlist to "all host", for backward compatibility
60 tdb 1.4 _hostList = "";
61 tdb 1.1 _logger.write(toString(), Logger.SYSINIT, "created");
62     }
63    
64     //---PUBLIC METHODS---
65 tdb 1.9
66     /**
67     * This method initiates the thread, setting things up, and then
68     * reading commands from the Client. It handles setting up of the
69     * DataHandler, and clean shutting down.
70     */
71 tdb 1.1 public void run() {
72     boolean run = true;
73 tdb 1.9 // Tell the client our protocol, and ask it for it's name
74 tdb 1.1 try {
75 tdb 1.12 send(PROTOVER);
76 tdb 1.1 _clientName = _socketIn.readLine();
77 tdb 1.11 if(_clientName==null) {
78 tdb 1.10 throw new IOException("Fatal error reading from client");
79     }
80 tdb 1.12 sendOK();
81 tdb 1.1 }
82     catch(IOException e) {
83     _logger.write(toString(), Logger.FATAL, "Fatal error, shutdown pending");
84     run=false;
85     }
86    
87 tdb 1.12 _logger.write(toString(), Logger.DEBUG, "Client has connected: "+_clientName);
88 tdb 1.1
89 tdb 1.9 // loop until we decide to shutdown (run=false)
90 tdb 1.1 while(run) {
91     try {
92     String cmd = _socketIn.readLine();
93 tdb 1.10 if(cmd==null) {
94     throw new IOException("Fatal error reading from client");
95     }
96 tdb 1.9 // make a decision about what to do
97 tdb 1.1 if(cmd.equals("STARTCONFIG")) {
98 tdb 1.9 // get the configuration for this client
99 tdb 1.1 Configuration myConfig = _configManager.getConfiguration("Client."+_clientName);
100 tdb 1.12 sendOK();
101 tdb 1.1 // get properties
102     cmd = _socketIn.readLine();
103 tdb 1.10 if(cmd==null) {
104     throw new IOException("Fatal error reading from client");
105     }
106 tdb 1.9 // provide all the requested properties
107 tdb 1.1 while(!cmd.equals("ENDCONFIG")) {
108 tdb 1.9 // client is restricted to this properties
109 tdb 1.7 if(cmd.startsWith("Client.") || cmd.startsWith("Host.")) {
110     try {
111     String returnedProperty = myConfig.getProperty(cmd);
112 tdb 1.12 send(returnedProperty);
113 tdb 1.7 }
114     catch (org.omg.CORBA.MARSHAL e) {
115 tdb 1.12 sendERROR();
116 tdb 1.7 }
117     }
118     else {
119 tdb 1.12 sendERROR();
120 tdb 1.1 }
121     cmd = _socketIn.readLine();
122 tdb 1.10 if(cmd==null) {
123     throw new IOException("Fatal error reading from client");
124     }
125 tdb 1.1 }
126 tdb 1.12 sendOK();
127     _logger.write(toString(), Logger.DEBUG, "Client has been configured");
128 tdb 1.1
129     }
130     else if(cmd.equals("STARTDATA")) {
131 tdb 1.9 // if we don't have a DataHandler, set one up
132 tdb 1.1 if(_dataHandler == null) {
133     // create a serversocket
134     ServerSocket ss = new ServerSocket(0);
135     // get the port
136 tdb 1.12 String port = new Integer(ss.getLocalPort()).toString();
137 tdb 1.9 // tell the client the port
138 tdb 1.12 send(port);
139 tdb 1.9 // wait for the client to connect
140 tdb 1.1 Socket s = ss.accept();
141     // when we get the Socket back, give it to the data thread
142 tdb 1.4 TCPDataHandler dh = new TCPDataHandler(s);
143 tdb 1.9 // register the DataHandler's queue, giving the host list
144     _packetSorter.register(dh.getQueue(), _hostList);
145 tdb 1.14 // startup a monitor on the DataHandler's queue, every minute
146 tdb 1.15 String queueName = _name + " TCPHandler:"+_socket.getInetAddress().getHostName();
147     dh.getQueue().startMonitor(_queueMonitorInterval*1000, _packetSorter.getQueue(), queueName);
148 tdb 1.9 // start up the DataHandler
149 tdb 1.2 dh.start();
150 tdb 1.9 // Hold a reference to the DataHandler, so we can stop it later
151 tdb 1.1 _dataHandler = dh;
152 tdb 1.12 sendOK();
153     _logger.write(toString(), Logger.DEBUG, "Data stream started at Clients Request on port: "+port);
154 tdb 1.1 }
155     else {
156 tdb 1.12 sendERROR();
157 tdb 1.1 }
158     }
159     else if(cmd.equals("STOPDATA")) {
160 tdb 1.12 // attempt to close the data channel
161     if(closeData()) {
162     sendOK();
163     _logger.write(toString(), Logger.DEBUG, "Data stream stopped at Clients Request");
164 tdb 1.1 }
165     else {
166 tdb 1.12 sendERROR();
167 tdb 1.1 }
168     }
169 tdb 1.4 else if(cmd.equals("SETHOSTLIST")) {
170 tdb 1.9 // we can only set the host list when
171     // the DataHandler is not connected
172 tdb 1.5 if(_dataHandler == null) {
173 tdb 1.12 sendOK();
174 tdb 1.9 // read and set the host list
175 tdb 1.5 cmd = _socketIn.readLine();
176 tdb 1.10 if(cmd==null) {
177     throw new IOException("Fatal error reading from client");
178     }
179 tdb 1.5 _hostList = cmd;
180 tdb 1.12 sendOK();
181 tdb 1.5 }
182     else {
183 tdb 1.12 sendERROR();
184 tdb 1.5 }
185 tdb 1.4 }
186 tdb 1.2 else if(cmd.equals("DISCONNECT")) {
187 tdb 1.12 // we going to disconnect, so lets stop the main loop
188 tdb 1.1 run=false;
189 tdb 1.9 // if there is a DataHandler, we'd best shut it down
190 tdb 1.12 if(closeData()) {
191     _logger.write(toString(), Logger.DEBUG, "Data stream stopped at Clients Request");
192 tdb 1.3 }
193 tdb 1.12 // say bye to the client
194     sendOK();
195 tdb 1.9 // close the reader, writer and Socket
196 tdb 1.1 _socketIn.close();
197     _socketOut.close();
198     _socket.close();
199 tdb 1.12 _logger.write(toString(), Logger.DEBUG, "Closing at Clients Request");
200 tdb 1.1 }
201     else {
202 tdb 1.12 sendERROR();
203 tdb 1.1 }
204     }
205     catch(IOException e) {
206 tdb 1.9 // if we get an exception, the client has probably left, so we stop
207 tdb 1.8 run=false;
208     _logger.write(toString(), Logger.FATAL, "Fatal communication error, shutdown pending");
209 tdb 1.1 }
210 tdb 1.17 }
211     // we'll close any DataHandlers here that shouldn't be open still
212     if(closeData()) {
213     _logger.write(toString(), Logger.DEBUG, "Data stream stopped due to fatal client error");
214 tdb 1.1 }
215 tdb 1.12 _logger.write(toString(), Logger.DEBUG, "Shutting down Control Handler, client has gone.");
216 tdb 1.1 }
217    
218     /**
219     * Overrides the {@link java.lang.Object#toString() Object.toString()}
220     * method to provide clean logging (every class should have this).
221     *
222     * This uses the uk.ac.ukc.iscream.util.NameFormat class
223     * to format the toString()
224     *
225     * @return the name of this class and its CVS revision
226     */
227     public String toString() {
228     return FormatName.getName(
229     _name,
230     getClass().getName(),
231     REVISION);
232     }
233    
234     //---PRIVATE METHODS---
235 tdb 1.12
236     /**
237     * Attempt to close down the DataHandler. This will return
238     * true if it managed to close it down, or false if there
239     * wasn't a DataHandler to close.
240     *
241     * @return whether the channel could be closed
242     */
243     private boolean closeData() {
244     // if we have a DataHandler, shut it down
245     if(_dataHandler != null) {
246     // Deregister the DataHandler, giving the host list
247     _packetSorter.deregister(_dataHandler.getQueue(), _hostList);
248     // Shut down the data handler
249     _dataHandler.shutdown();
250     // Destroy our reference, leaving it for the GC
251     _dataHandler = null;
252     return true;
253     }
254     else {
255     return false;
256     }
257     }
258    
259     /**
260     * Send an OK message to the outgoing Socket
261     */
262     private void sendOK() {
263     send("OK");
264     }
265    
266     /**
267     * Send an ERROR message to the outgoing Socket.
268     */
269     private void sendERROR() {
270     send("ERROR");
271     }
272    
273     /**
274     * Send any String message to the outgoing Socket.
275     *
276     * @param message The message/command to send.
277     */
278     private void send(String message) {
279     _socketOut.println(message);
280     }
281 tdb 1.1
282     //---ACCESSOR/MUTATOR METHODS---
283    
284     //---ATTRIBUTES---
285    
286     /**
287     * This is the friendly identifier of the
288     * component this class is running in.
289     * eg, a Filter may be called "filter1",
290     * If this class does not have an owning
291     * component, a name from the configuration
292     * can be placed here. This name could also
293     * be changed to null for utility classes.
294     */
295     private String _name = ClientInterfaceMain.NAME;
296    
297     /**
298     * This holds a reference to the
299     * system logger that is being used.
300     */
301     private Logger _logger = ReferenceManager.getInstance().getLogger();
302    
303     /**
304     * A reference to the Configuration Manager the system is using
305     */
306     private ConfigurationManager _configManager = ReferenceManager.getInstance().getCM();
307    
308     /**
309     * The socket we are talking on
310     */
311     private Socket _socket;
312    
313     /**
314     * A hook to the inbound data from the socket
315     */
316     private BufferedReader _socketIn;
317    
318     /**
319     * A hook to the outbound stream for the socket
320     */
321     private PrintWriter _socketOut;
322 tdb 1.4
323 tdb 1.1 /**
324 tdb 1.4 * A reference to the PacketSorter.
325     */
326 tdb 1.9 private PacketSorter _packetSorter;
327 tdb 1.1
328 tdb 1.9 /**
329     * A reference to the DataHandler, if there is one
330     */
331 tdb 1.1 private TCPDataHandler _dataHandler;
332    
333 tdb 1.9 /**
334     * The name of the Client we're connected to
335     */
336 tdb 1.1 private String _clientName;
337 tdb 1.9
338     /**
339     * The host list the Client has requested
340     */
341 tdb 1.4 private String _hostList;
342 tdb 1.15
343     /**
344     * The interval at which to monitor our Queue
345     */
346     private int _queueMonitorInterval;
347 tdb 1.1
348     //---STATIC ATTRIBUTES---
349    
350     }