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.21
Committed: Sat Mar 17 03:57:38 2001 UTC (23 years, 2 months ago) by tdb
Branch: MAIN
Changes since 1.20: +5 -5 lines
Log Message:
Missed this bit when plugging in the ConfigurationProxy.

File Contents

# User Rev Content
1 tdb 1.1 //---PACKAGE DECLARATION---
2 tdb 1.20 package uk.org.iscream.clientinterface;
3 tdb 1.1
4     //---IMPORTS---
5 tdb 1.20 import uk.org.iscream.util.*;
6     import uk.org.iscream.componentmanager.*;
7     import uk.org.iscream.core.*;
8 tdb 1.1 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.21 * @version $Id: TCPControlHandler.java,v 1.20 2001/03/14 23:25:29 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.21 public final String REVISION = "$Revision: 1.20 $";
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 tdb 1.19 public TCPControlHandler(Socket socket, PacketSorter packetSorter) throws IOException {
52 tdb 1.18 // set the Thread name
53     setName("clientinterface.TCPControlHandler");
54    
55 tdb 1.1 _socket = socket;
56 tdb 1.9 _packetSorter = packetSorter;
57     // setup the reader & writer
58 tdb 1.1 _socketIn = new BufferedReader(new InputStreamReader(_socket.getInputStream()));
59 tdb 1.13 _socketOut = new PrintWriter(_socket.getOutputStream(), true);
60 tdb 1.9 // set the default hostlist to "all host", for backward compatibility
61 tdb 1.4 _hostList = "";
62 tdb 1.1 _logger.write(toString(), Logger.SYSINIT, "created");
63     }
64    
65     //---PUBLIC METHODS---
66 tdb 1.9
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 tdb 1.1 public void run() {
73     boolean run = true;
74 tdb 1.9 // Tell the client our protocol, and ask it for it's name
75 tdb 1.1 try {
76 tdb 1.12 send(PROTOVER);
77 tdb 1.1 _clientName = _socketIn.readLine();
78 tdb 1.11 if(_clientName==null) {
79 tdb 1.10 throw new IOException("Fatal error reading from client");
80     }
81 tdb 1.12 sendOK();
82 tdb 1.1 }
83     catch(IOException e) {
84     _logger.write(toString(), Logger.FATAL, "Fatal error, shutdown pending");
85     run=false;
86     }
87    
88 tdb 1.12 _logger.write(toString(), Logger.DEBUG, "Client has connected: "+_clientName);
89 tdb 1.1
90 tdb 1.9 // loop until we decide to shutdown (run=false)
91 tdb 1.1 while(run) {
92     try {
93     String cmd = _socketIn.readLine();
94 tdb 1.10 if(cmd==null) {
95     throw new IOException("Fatal error reading from client");
96     }
97 tdb 1.9 // make a decision about what to do
98 tdb 1.1 if(cmd.equals("STARTCONFIG")) {
99 tdb 1.9 // get the configuration for this client
100 tdb 1.21 ConfigurationProxy cp = ConfigurationProxy.getInstance();
101 tdb 1.12 sendOK();
102 tdb 1.1 // get properties
103     cmd = _socketIn.readLine();
104 tdb 1.10 if(cmd==null) {
105     throw new IOException("Fatal error reading from client");
106     }
107 tdb 1.9 // provide all the requested properties
108 tdb 1.1 while(!cmd.equals("ENDCONFIG")) {
109 tdb 1.9 // client is restricted to this properties
110 tdb 1.7 if(cmd.startsWith("Client.") || cmd.startsWith("Host.")) {
111     try {
112 tdb 1.21 String returnedProperty = cp.getProperty("Client."+_clientName, cmd);
113 tdb 1.12 send(returnedProperty);
114 tdb 1.7 }
115 tdb 1.21 catch (PropertyNotFoundException e) {
116 tdb 1.12 sendERROR();
117 tdb 1.7 }
118     }
119     else {
120 tdb 1.12 sendERROR();
121 tdb 1.1 }
122     cmd = _socketIn.readLine();
123 tdb 1.10 if(cmd==null) {
124     throw new IOException("Fatal error reading from client");
125     }
126 tdb 1.1 }
127 tdb 1.12 sendOK();
128     _logger.write(toString(), Logger.DEBUG, "Client has been configured");
129 tdb 1.1
130     }
131     else if(cmd.equals("STARTDATA")) {
132 tdb 1.9 // if we don't have a DataHandler, set one up
133 tdb 1.1 if(_dataHandler == null) {
134     // create a serversocket
135     ServerSocket ss = new ServerSocket(0);
136     // get the port
137 tdb 1.12 String port = new Integer(ss.getLocalPort()).toString();
138 tdb 1.9 // tell the client the port
139 tdb 1.12 send(port);
140 tdb 1.9 // wait for the client to connect
141 tdb 1.1 Socket s = ss.accept();
142     // when we get the Socket back, give it to the data thread
143 tdb 1.4 TCPDataHandler dh = new TCPDataHandler(s);
144 tdb 1.9 // register the DataHandler's queue, giving the host list
145     _packetSorter.register(dh.getQueue(), _hostList);
146 tdb 1.19 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 tdb 1.9 // start up the DataHandler
156 tdb 1.2 dh.start();
157 tdb 1.9 // Hold a reference to the DataHandler, so we can stop it later
158 tdb 1.1 _dataHandler = dh;
159 tdb 1.12 sendOK();
160     _logger.write(toString(), Logger.DEBUG, "Data stream started at Clients Request on port: "+port);
161 tdb 1.1 }
162     else {
163 tdb 1.12 sendERROR();
164 tdb 1.1 }
165     }
166     else if(cmd.equals("STOPDATA")) {
167 tdb 1.12 // attempt to close the data channel
168     if(closeData()) {
169     sendOK();
170     _logger.write(toString(), Logger.DEBUG, "Data stream stopped at Clients Request");
171 tdb 1.1 }
172     else {
173 tdb 1.12 sendERROR();
174 tdb 1.1 }
175     }
176 tdb 1.4 else if(cmd.equals("SETHOSTLIST")) {
177 tdb 1.9 // we can only set the host list when
178     // the DataHandler is not connected
179 tdb 1.5 if(_dataHandler == null) {
180 tdb 1.12 sendOK();
181 tdb 1.9 // read and set the host list
182 tdb 1.5 cmd = _socketIn.readLine();
183 tdb 1.10 if(cmd==null) {
184     throw new IOException("Fatal error reading from client");
185     }
186 tdb 1.5 _hostList = cmd;
187 tdb 1.12 sendOK();
188 tdb 1.5 }
189     else {
190 tdb 1.12 sendERROR();
191 tdb 1.5 }
192 tdb 1.4 }
193 tdb 1.2 else if(cmd.equals("DISCONNECT")) {
194 tdb 1.12 // we going to disconnect, so lets stop the main loop
195 tdb 1.1 run=false;
196 tdb 1.9 // if there is a DataHandler, we'd best shut it down
197 tdb 1.12 if(closeData()) {
198     _logger.write(toString(), Logger.DEBUG, "Data stream stopped at Clients Request");
199 tdb 1.3 }
200 tdb 1.12 // say bye to the client
201     sendOK();
202 tdb 1.9 // close the reader, writer and Socket
203 tdb 1.1 _socketIn.close();
204     _socketOut.close();
205     _socket.close();
206 tdb 1.12 _logger.write(toString(), Logger.DEBUG, "Closing at Clients Request");
207 tdb 1.1 }
208     else {
209 tdb 1.12 sendERROR();
210 tdb 1.1 }
211     }
212     catch(IOException e) {
213 tdb 1.9 // if we get an exception, the client has probably left, so we stop
214 tdb 1.8 run=false;
215     _logger.write(toString(), Logger.FATAL, "Fatal communication error, shutdown pending");
216 tdb 1.1 }
217 tdb 1.17 }
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 tdb 1.1 }
222 tdb 1.12 _logger.write(toString(), Logger.DEBUG, "Shutting down Control Handler, client has gone.");
223 tdb 1.1 }
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 tdb 1.20 * This uses the uk.org.iscream.util.NameFormat class
230 tdb 1.1 * 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 tdb 1.12
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 tdb 1.1
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 tdb 1.4
330 tdb 1.1 /**
331 tdb 1.4 * A reference to the PacketSorter.
332     */
333 tdb 1.9 private PacketSorter _packetSorter;
334 tdb 1.1
335 tdb 1.9 /**
336     * A reference to the DataHandler, if there is one
337     */
338 tdb 1.1 private TCPDataHandler _dataHandler;
339    
340 tdb 1.9 /**
341     * The name of the Client we're connected to
342     */
343 tdb 1.1 private String _clientName;
344 tdb 1.9
345     /**
346     * The host list the Client has requested
347     */
348 tdb 1.4 private String _hostList;
349 tdb 1.1
350     //---STATIC ATTRIBUTES---
351    
352     }