C:\Java WorkShop\Lexx\src\lexx\server\http\ClientHttp.java

1    package lexx.server.http; 
2     
3    import java.io.DataInputStream; 
4    import java.io.File; 
5    import java.io.InputStream; 
6    import java.util.Vector; 
7     
8    import java.awt.BorderLayout; 
9    import java.awt.event.KeyEvent; 
10   import java.awt.event.KeyListener; 
11   import javax.swing.JLabel; 
12   import javax.swing.JOptionPane; 
13   import javax.swing.JPanel; 
14   import javax.swing.JScrollPane; 
15   import javax.swing.JTextArea; 
16   import javax.swing.JTextField; 
17    
18   import example.HttpClient; 
19   import example.HttpListener; 
20   import lexx.gui.EditorFrame; 
21   import lexx.server.Chat; 
22   import lexx.server.ClientBase; 
23   import lexx.server.HashProperties; 
24   import lexx.server.RequestedFile; 
25   import lexx.server.socket.Server; 
26    
27   /** 
28    * <p>Client uses the HTTP protocol to communicate<</p> 
29    * <p>Due to the limitations of HTTP protocol the client will need to connect to 
30    * server continously to enable <b>full duplex</b> communication</p> 
31    * <p>Copyright (c) 2002-2003</p> 
32    * @since 20/03/2003 
33    * @author Mohammed Imran 
34    * @version 1.0 
35    */ 
36   public final class ClientHttp implements HttpListener, ClientBase 
37   { 
38     private static final org.apache.log4j.Logger log = org.apache.log4j.Logger. 
39         getLogger(ClientHttp.class); 
40     private final JPanel panel = new JPanel(); 
41     private final JTextArea text = new JTextArea(); 
42     private final JTextField field = new JTextField(); 
43     private int clientNum = 1; 
44     private final JLabel usersNum = new JLabel("Number of users online = 1"); 
45     private JLabel status = null; 
46    
47     private final HttpClient _client; 
48    
49     /** 
50      * Downloads all the changed files from the server 
51      */ 
52     public final void updateMyFiles() 
53     { 
54       this.send(c.sendMeHash()); 
55     } 
56    
57     /** 
58      * Uploads all the changed files to the server 
59      */ 
60     public final void updateServer() 
61     { 
62       this.send(c.sendHashProperties(HashProperties.hashCurrentProject(lexx.utils. 
63           Config.getProjectPath()))); 
64     } 
65    
66     private final Vector messages = new Vector(); 
67    
68     private void send(String message) 
69     { 
70       messages.add("USERNAME=" + username + '&' + message); 
71     } 
72    
73     /** 
74      * Used if you would like to log when the client performs a task 
75      * @param l where the text will be logged 
76      */ 
77     public final void setStatus(JLabel newStatus) 
78     { 
79       status = newStatus; 
80     } 
81    
82     /** 
83      * Tells you the number of clients that are on-line 
84      * @return numner of clients that are on-line 
85      */ 
86     public final int getClientNum() 
87     { 
88       return clientNum; 
89     } 
90    
91     private final String username; 
92    
93     public ClientHttp(String url, String userName) throws Exception 
94     { 
95       username = userName; 
96       _client = new HttpClient(url); 
97       _client.addHttpListener(this); 
98    
99       new Thread() 
100      { 
101        public void run() 
102        { 
103          int i = 0; 
104   
105          while(true) 
106          { 
107            try 
108            { 
109              String send = "Dummy Message"; 
110              if(!messages.isEmpty()) 
111              { 
112                send = messages.get(0).toString(); 
113                messages.remove(0); 
114              } 
115              String response = new String(_client.send(send.getBytes())); 
116              Chat.sent += send.length(); 
117              Chat.receieved += response.length(); 
118   
119              if(log.isDebugEnabled()) 
120              { 
121                log.debug("Sent: " + send); 
122                log.debug("Recieved: " + response); 
123              } 
124              handleMessage(response); 
125              Thread.sleep(1000); 
126            } 
127            catch(Exception ex) 
128            { 
129              log.fatal(ex, ex); 
130              JOptionPane.showMessageDialog(panel, 
131                  "You have been disconnected from server, please reconnect", 
132                  "Unable to connect to server", 
133                  JOptionPane.ERROR_MESSAGE); 
134            } 
135          } 
136        } 
137      }.start(); 
138   
139      panel.setLayout(new BorderLayout()); 
140   
141      panel.add(new JScrollPane(text), BorderLayout.CENTER); 
142      panel.add(field, BorderLayout.SOUTH); 
143      panel.add(usersNum, BorderLayout.NORTH); 
144   
145      new Thread() 
146      { 
147        public void run() 
148        { 
149          this.setPriority(Thread.MIN_PRIORITY); 
150          while(true) 
151          { 
152            try 
153            { 
154              usersNum.setText("Number of users online = " + clientNum + 
155                               ",         Sent " + 
156                               ( (int) (Chat.sent / 1024)) + "Kb, Recieved " + 
157                               ( (int) (Chat.receieved / 1024)) + "Kb"); 
158              this.sleep(2000); 
159            } 
160            catch(InterruptedException ex) 
161            { 
162              log.fatal(ex, ex); 
163            } 
164          } 
165        } 
166      }.start(); 
167   
168      field.addKeyListener(new KeyListener() 
169      { 
170        public void keyTyped(KeyEvent e) 
171        { 
172          if(e.getKeyChar() == '\n' || e.getKeyChar() == '\r') 
173          { 
174            if(field.getText() != null && !"".equals(field.getText())) 
175            { 
176              send(new Chat().sendMessage("[" + username + "] " + field.getText())); 
177              field.setText(""); 
178            } 
179          } 
180        } 
181   
182        public void keyPressed(KeyEvent e) 
183        {} 
184   
185        public void keyReleased(KeyEvent e) 
186        {} 
187      }); 
188   
189      this.updateMyFiles(); 
190    } 
191   
192    public final void service(InputStream data) 
193    { 
194      try 
195      { 
196        DataInputStream input = new DataInputStream(data); 
197        String s = Chat.getMessage(input); 
198        Chat.receieved += s.length(); 
199        this.handleMessage(s); 
200   
201  //      System.out.println("Recieved: " + s); 
202        input.close(); 
203      } 
204      catch(Exception ex) 
205      { 
206        JOptionPane.showMessageDialog(panel, 
207            "You have been disconnected from server, please reconnect", 
208            "Unable to connect to server", 
209            JOptionPane.ERROR_MESSAGE); 
210        log.fatal(ex, ex); 
211      } 
212    } 
213   
214    /** 
215     * Usage: java TestClient <url> <send timeout> 
216     */ 
217    public static void main(String argv[]) throws Exception 
218    { 
219      if(argv.length == 2) 
220      { 
221        new ClientHttp(argv[0], "lexx" + Math.random()); 
222      } 
223      else 
224      { 
225        System.out.println("Usage: java TestClient <url> <send timeout>"); 
226        System.exit(1); 
227      } 
228    } 
229   
230    private void handleMessage(String message) 
231    { 
232      status = lexx.utils.Config.getStatusLabel(); 
233   
234      if(message.startsWith("ALL")) 
235      { 
236        message = message.substring("ALL".length(), message.length()); 
237   
238      } 
239      if(message.startsWith("USERNAME")) 
240      { 
241        for(int i = "USERNAME".length() + 1; i < message.length(); i++) 
242        { 
243          if(message.charAt(i) == '&') 
244          { 
245            String name = message.substring("USERNAME".length() + 1, i); 
246   
247            if(!username.equals(name)) 
248            { 
249              return; //i don't need it 
250            } 
251            message = message.substring(i + 1, message.length()); 
252            break; 
253          } 
254        } 
255      } 
256   
257      if(message.startsWith(Server.MESSAGE)) //recieved a message 
258      { 
259        text.append(c.recievedMessage(message).trim() + '\n'); 
260        text.setCaretPosition(text.getText().length()); 
261   
262        if(lexx.utils.Config.getFrameForDialog()instanceof EditorFrame) 
263        { 
264          EditorFrame f = (EditorFrame) lexx.utils.Config.getFrameForDialog(); 
265          f.setLowerTabSelect(this.getPanel()); 
266        } 
267      } 
268   
269      if(message.startsWith(Server.REQUESTFILE)) //tells me if someone is using that file 
270      { 
271        //String fileName = c.getRequestedFile(message).getFilename(); 
272        reqFileAns.add(c.getRequestedFile(message)); 
273      } 
274   
275      if(message.startsWith(Server.FILENAME)) //wants send me a file 
276      { 
277        File f = c.createFile(message, lexx.utils.Config.getProjectPath(), true); 
278   
279        if(status != null) 
280        { 
281          status.setText("Recieved file from server - " + f.getName()); 
282        } 
283      } 
284   
285      if(message.startsWith(Server.HASHPROPERTIES)) //updating server files from clients 
286      { 
287        if(status != null) 
288        { 
289          status.setText("Recieved list of files contained on server"); 
290   
291        } 
292        HashProperties hash = HashProperties.hashCurrentProject(lexx.utils.Config. 
293            getProjectPath()); 
294        HashProperties newHash = c.getHashProperties(message); 
295        java.util.List diff = HashProperties.getDifferentFiles(hash, newHash); 
296   
297        if(waitCache) 
298        { 
299          serverHash = newHash; 
300   
301          if(waitCache2) 
302          { 
303            return; 
304          } 
305          else 
306          { 
307            waitCache2 = true; 
308          } 
309        } 
310   
311        for(int i = 0; i < diff.size(); i++) 
312        { //requesting different files 
313          if(status != null) 
314          { 
315            status.setText("Requesting " + diff.get(i).toString() + 
316                           " from server"); 
317          } 
318          this.send(c.sendMeFile(diff.get(i).toString())); 
319        } 
320        this.send(Server.END_OF_FILES); 
321      } 
322   
323      if(message.startsWith(Server.END_OF_FILES)) 
324      { //backup messure ensuring waitForCache never waits for ever 
325        waitCache = false; 
326        waitCache2 = false; 
327        serverHash = null; 
328      } 
329   
330      if(message.startsWith(Server.SENDMEHASH)) //send my hashproperties 
331      { 
332        if(status != null) 
333        { 
334          status.setText("Sending my list of files to server"); 
335        } 
336        this.send(c.sendHashProperties(HashProperties.hashCurrentProject(lexx. 
337            utils.Config.getProjectPath()))); 
338        if(status != null) 
339        { 
340          status.setText(""); 
341        } 
342      } 
343   
344      if(message.startsWith(Server.SENDMEFILE)) //send user a file 
345      { 
346        String filename = c.getSendFileName(message); 
347        if(status != null) 
348        { 
349          status.setText("Sending server " + filename + " file"); 
350        } 
351        this.send(c.sendFile(new File(lexx.utils.Config.getProjectPath() + File.separatorChar + 
352                                      filename), lexx.utils.Config.getProjectPath(), true)); 
353        if(status != null) 
354        { 
355          status.setText(""); 
356        } 
357      } 
358   
359      if(message.startsWith(Server.CLIENT_NUM)) //updating number of clients 
360      { 
361        clientNum = c.getClientNum(message); 
362        usersNum.setText("Number of users online = " + clientNum); 
363        if(lexx.utils.Config.getFrameForDialog()instanceof EditorFrame) 
364        { 
365          EditorFrame f = (EditorFrame) lexx.utils.Config.getFrameForDialog(); 
366          f.setLowerTabSelect(this.getPanel()); 
367        } 
368      } 
369    } 
370   
371    /** 
372     * The GUI for instant messaging. It should contain inside it all the interactions 
373     * required for chatting on-line. 
374     * @return panel for instant messaging 
375     */ 
376    public final JPanel getPanel() 
377    { 
378      return panel; 
379    } 
380   
381    private boolean waitCache = false; 
382    private boolean waitCache2 = false; 
383   
384    /** 
385     * Sends the file to the server 
386     * @param f the file you wish to send 
387     */ 
388    public final void sendFile(File f) 
389    { 
390      String filename = f.toString(); 
391   
392      if(filename.startsWith(lexx.utils.Config.getProjectPath())) 
393      { 
394        filename = filename.substring(lexx.utils.Config.getProjectPath().length() + 
395                                      1, filename.length()); 
396   
397      } 
398      if(status != null) 
399      { 
400        status.setText("Sending server " + filename + " file"); 
401      } 
402      this.send(c.sendFile(f, lexx.utils.Config.getProjectPath(), true)); 
403      if(status != null) 
404      { 
405        status.setText(""); 
406      } 
407    } 
408   
409    /** 
410     * This is called when you call the updataMyFiles() method, as it waits until 
411     * all the files have been successfully updated 
412     */ 
413    public final void waitUtilCached() 
414    { 
415      waitCache = true; 
416      this.updateMyFiles(); 
417      long recieved = Chat.receieved; 
418   
419      while(waitCache) 
420      { 
421        recieved = Chat.receieved; 
422        if(serverHash != null) 
423        { 
424          boolean hasUpdated = HashProperties.getDifferentFiles( 
425              HashProperties.hashCurrentProject(lexx.utils.Config.getProjectPath()), 
426              serverHash).size() == 0; 
427   
428          if(hasUpdated) 
429          { 
430            waitCache = false; 
431            waitCache2 = false; 
432            serverHash = null; 
433            return; 
434          } 
435        } 
436        try 
437        { 
438          Thread.sleep(5000); 
439          if(recieved == Chat.receieved) 
440          { 
441            this.send(c.sendMeHash()); 
442          } 
443   
444          recieved = Chat.receieved; 
445        } 
446        catch(InterruptedException ex) 
447        { 
448          log.fatal(ex, ex); 
449        } 
450      } 
451    } 
452   
453    private final Chat c = new Chat(); 
454    private final Vector reqFileAns = new Vector(); 
455   
456    /** 
457     * Unlocks the file when you have finished with it, so other clients can use it 
458     * @param filename name of the file you have just unlocked 
459     */ 
460    public final void releaseFile(String filename) 
461    { 
462      if(filename.startsWith(lexx.utils.Config.getProjectPath())) 
463      { 
464        filename = filename.substring(lexx.utils.Config.getProjectPath().length() + 
465                                      1, filename.length()); 
466   
467      } 
468      this.send(c.sendRequestedFile(filename, false)); 
469    } 
470   
471    private HashProperties serverHash = null; 
472   
473    /** 
474     * Requset of file for editing 
475     * @param filename the name of the file you wish to edit 
476     * @return tells you if someone else has locked the file 
477     */ 
478    public final boolean requestFile(String filename) 
479    { 
480      if(filename.startsWith(lexx.utils.Config.getProjectPath())) 
481      { 
482        filename = filename.substring(lexx.utils.Config.getProjectPath().length() + 
483                                      1, filename.length()); 
484   
485      } 
486      this.send(c.sendRequestedFile(filename, true)); //want this file 
487   
488      while(true) //clientNum > 1) 
489      { 
490        try 
491        { 
492          Thread.sleep(500); 
493          for(int i = 0; i < reqFileAns.size(); i++) 
494          { 
495            RequestedFile r = (RequestedFile) reqFileAns.get(i); 
496            if(r.getFilename().equals(filename)) 
497            { 
498              reqFileAns.remove(r); 
499              return r.canHaveFile(); 
500            } 
501          } 
502        } 
503        catch(InterruptedException ex) 
504        { 
505          log.fatal(ex, ex); 
506        } 
507      } 
508    } 
509  }