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.14
Committed: Mon Feb 12 02:23:53 2001 UTC (23 years, 3 months ago) by tdb
Branch: MAIN
Changes since 1.13: +4 -2 lines
Log Message:
Now monitor the Queue here every 60 seconds, reporting back to the Queue in
the PacketSorter class.

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