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

# Content
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 * @author $Author: tdb1 $
22 * @version $Id: TCPControlHandler.java,v 1.16 2001/02/26 00:58:25 tdb1 Exp $
23 */
24 class TCPControlHandler extends Thread {
25
26 //---FINAL ATTRIBUTES---
27
28 /**
29 * The current CVS revision of this class
30 */
31 public final String REVISION = "$Revision: 1.16 $";
32
33 /**
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 public static final String PROTOVER = "PROTOCOL 1.1";
39
40 //---STATIC METHODS---
41
42 //---CONSTRUCTORS---
43
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 * @param queueMonitorInterval The interval at which to monitor our Queue
51 */
52 public TCPControlHandler(Socket socket, PacketSorter packetSorter, int queueMonitorInterval) throws IOException {
53 _socket = socket;
54 _packetSorter = packetSorter;
55 _queueMonitorInterval = queueMonitorInterval;
56 // setup the reader & writer
57 _socketIn = new BufferedReader(new InputStreamReader(_socket.getInputStream()));
58 _socketOut = new PrintWriter(_socket.getOutputStream(), true);
59 // set the default hostlist to "all host", for backward compatibility
60 _hostList = "";
61 _logger.write(toString(), Logger.SYSINIT, "created");
62 }
63
64 //---PUBLIC METHODS---
65
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 public void run() {
72 boolean run = true;
73 // Tell the client our protocol, and ask it for it's name
74 try {
75 send(PROTOVER);
76 _clientName = _socketIn.readLine();
77 if(_clientName==null) {
78 throw new IOException("Fatal error reading from client");
79 }
80 sendOK();
81 }
82 catch(IOException e) {
83 _logger.write(toString(), Logger.FATAL, "Fatal error, shutdown pending");
84 run=false;
85 }
86
87 _logger.write(toString(), Logger.DEBUG, "Client has connected: "+_clientName);
88
89 // loop until we decide to shutdown (run=false)
90 while(run) {
91 try {
92 String cmd = _socketIn.readLine();
93 if(cmd==null) {
94 throw new IOException("Fatal error reading from client");
95 }
96 // make a decision about what to do
97 if(cmd.equals("STARTCONFIG")) {
98 // get the configuration for this client
99 Configuration myConfig = _configManager.getConfiguration("Client."+_clientName);
100 sendOK();
101 // get properties
102 cmd = _socketIn.readLine();
103 if(cmd==null) {
104 throw new IOException("Fatal error reading from client");
105 }
106 // provide all the requested properties
107 while(!cmd.equals("ENDCONFIG")) {
108 // client is restricted to this properties
109 if(cmd.startsWith("Client.") || cmd.startsWith("Host.")) {
110 try {
111 String returnedProperty = myConfig.getProperty(cmd);
112 send(returnedProperty);
113 }
114 catch (org.omg.CORBA.MARSHAL e) {
115 sendERROR();
116 }
117 }
118 else {
119 sendERROR();
120 }
121 cmd = _socketIn.readLine();
122 if(cmd==null) {
123 throw new IOException("Fatal error reading from client");
124 }
125 }
126 sendOK();
127 _logger.write(toString(), Logger.DEBUG, "Client has been configured");
128
129 }
130 else if(cmd.equals("STARTDATA")) {
131 // if we don't have a DataHandler, set one up
132 if(_dataHandler == null) {
133 // create a serversocket
134 ServerSocket ss = new ServerSocket(0);
135 // get the port
136 String port = new Integer(ss.getLocalPort()).toString();
137 // tell the client the port
138 send(port);
139 // wait for the client to connect
140 Socket s = ss.accept();
141 // when we get the Socket back, give it to the data thread
142 TCPDataHandler dh = new TCPDataHandler(s);
143 // register the DataHandler's queue, giving the host list
144 _packetSorter.register(dh.getQueue(), _hostList);
145 // startup a monitor on the DataHandler's queue, every minute
146 String queueName = _name + " TCPHandler:"+_socket.getInetAddress().getHostName();
147 dh.getQueue().startMonitor(_queueMonitorInterval*1000, _packetSorter.getQueue(), queueName);
148 // start up the DataHandler
149 dh.start();
150 // Hold a reference to the DataHandler, so we can stop it later
151 _dataHandler = dh;
152 sendOK();
153 _logger.write(toString(), Logger.DEBUG, "Data stream started at Clients Request on port: "+port);
154 }
155 else {
156 sendERROR();
157 }
158 }
159 else if(cmd.equals("STOPDATA")) {
160 // attempt to close the data channel
161 if(closeData()) {
162 sendOK();
163 _logger.write(toString(), Logger.DEBUG, "Data stream stopped at Clients Request");
164 }
165 else {
166 sendERROR();
167 }
168 }
169 else if(cmd.equals("SETHOSTLIST")) {
170 // we can only set the host list when
171 // the DataHandler is not connected
172 if(_dataHandler == null) {
173 sendOK();
174 // read and set the host list
175 cmd = _socketIn.readLine();
176 if(cmd==null) {
177 throw new IOException("Fatal error reading from client");
178 }
179 _hostList = cmd;
180 sendOK();
181 }
182 else {
183 sendERROR();
184 }
185 }
186 else if(cmd.equals("DISCONNECT")) {
187 // we going to disconnect, so lets stop the main loop
188 run=false;
189 // if there is a DataHandler, we'd best shut it down
190 if(closeData()) {
191 _logger.write(toString(), Logger.DEBUG, "Data stream stopped at Clients Request");
192 }
193 // say bye to the client
194 sendOK();
195 // close the reader, writer and Socket
196 _socketIn.close();
197 _socketOut.close();
198 _socket.close();
199 _logger.write(toString(), Logger.DEBUG, "Closing at Clients Request");
200 }
201 else {
202 sendERROR();
203 }
204 }
205 catch(IOException e) {
206 // if we get an exception, the client has probably left, so we stop
207 run=false;
208 _logger.write(toString(), Logger.FATAL, "Fatal communication error, shutdown pending");
209 }
210 }
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 }
215 _logger.write(toString(), Logger.DEBUG, "Shutting down Control Handler, client has gone.");
216 }
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
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
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
323 /**
324 * A reference to the PacketSorter.
325 */
326 private PacketSorter _packetSorter;
327
328 /**
329 * A reference to the DataHandler, if there is one
330 */
331 private TCPDataHandler _dataHandler;
332
333 /**
334 * The name of the Client we're connected to
335 */
336 private String _clientName;
337
338 /**
339 * The host list the Client has requested
340 */
341 private String _hostList;
342
343 /**
344 * The interval at which to monitor our Queue
345 */
346 private int _queueMonitorInterval;
347
348 //---STATIC ATTRIBUTES---
349
350 }