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.19
Committed: Tue Mar 13 18:37:08 2001 UTC (23 years, 2 months ago) by tdb
Branch: MAIN
Changes since 1.18: +12 -13 lines
Log Message:
Now makes use of the ConfigurationProxy.

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