Internet Programming with Java Course

2.4.Ïðèìåð: Ðàçðàáîòêà íà chat àïëåò

Creating Applet Client for NakovChatServer

/**

 * Chat applet client for Nakov Chat Server.

 * Author: Nikolay Nedyalkov, 2002

 *

 * ChatApplet class provides applet-based graphical user interface

 * for the clients of NakovChatServer.

 */

import java.awt.*;

import java.awt.event.*;

import java.applet.*;

import java.util.Vector;

import java.util.Enumeration;

 

public class ChatApplet extends Applet implements ActionListener, MouseListener {

     boolean isStandalone = false;

 

     private ChatClient cl           = new ChatClient (this);

     private PopupMenu popupMenu1    = new PopupMenu ();

     private MenuItem menuItem1      = new MenuItem ();

     private MenuItem menuItem2      = new MenuItem ();

     private Vector allUsers         = new Vector ();

     private Vector deniedUsers      = new Vector ();

     private boolean isConnected     = false;

 

     private TextField textField1    = new TextField();

     private Button connectButton    = new Button ();

     private Button disconnectButton = new Button ();

     private Button sendButton       = new Button ();

     private Button clearButton      = new Button ();

     private Button exitButton       = new Button ();

 

     public TextArea textArea1      = new TextArea();

     public List list1              = new List();

 

     public void setConnected(boolean aConnected) {

          isConnected = aConnected;

     }

 

     public boolean getConnected()   {

          return isConnected;

     }

 

     /**

      * Method is called from ChatClient to get reference to ChatApplet.textArea1.

      * @return java.awt.TextArea

      */

     public TextArea getTextArea () {

          return textArea1;

     }

 

     /**

      * Method is called from ChatClient to get reference to ChatApplet.list1.

      * @return java.awt.List

      */

     public List getList () {

          return list1;

     }

 

     /**

      * Method is called from ChatClient to register anUser in allUsers vector

      * and list1 visual control.

      * @param anUser - user to be included.

      */

     public synchronized void addUser (String anUser) {

          if (!allUsers.contains(anUser)) {

               allUsers.addElement (anUser);

               list1.add (anUser);

          }

     }

 

     /**

      * Method is called from ChatClient to append given message to the

      * ChatApplet's TextArea. It also checks whether anUser is in our

      * Ignore list and ignores the message in this case.

      * @param anUser - user that have sent the message

      * @param aText - message to be appened to the applet's TextArea

      */

     public synchronized void addText (String aText, String anUser) {

          if (!deniedUsers.contains(anUser)) {

               textArea1.append (aText + "\n");

          }

     }

 

     public synchronized void addSystemMessage(String aText) {

          textArea1.append(aText + "\n");

     }

 

     /**

      * Applet life cycle initiliazation.

      */

     public void init() {

          try {

               jbInit();

          }

          catch(Exception e) {

               e.printStackTrace();

          }

     }

 

     /**

      * Component initialization.

      * @throws Exception

      */

     private void jbInit() throws Exception {

          this.setLayout (null);

 

          // -- Begin buttons section

          sendButton.setLabel("Send");

          sendButton.setBounds (new Rectangle(316, 245, 68, 23));

          sendButton.addActionListener (this);

          this.add(sendButton);

 

          connectButton.setLabel("connect");

          connectButton.setBounds(new Rectangle(34, 270, 95, 22));

          connectButton.addActionListener(this);

          this.add(connectButton, null);

 

          disconnectButton.addActionListener(this);

          disconnectButton.setBounds(new Rectangle(175, 270, 108, 22));

          disconnectButton.setLabel("disconnect");

          this.add(disconnectButton, null);

 

          clearButton.setLabel("Clear");

          clearButton.addActionListener(this);

          clearButton.setBounds(new Rectangle(316, 270, 68, 23));

          this.add(clearButton, null);

 

          exitButton.setBackground(Color.gray);

          exitButton.setForeground(Color.lightGray);

          exitButton.setLabel("Q");

          exitButton.setBounds(new Rectangle(388, 245, 32, 48));

          exitButton.addActionListener(this);

          this.add(exitButton, null);

          // -- End buttons section

 

          // -- Begin edit controls

          textField1.setBounds(new Rectangle(10, 245, 303, 23));

          textField1.addActionListener(this);

          textField1.setBackground(Color.lightGray);

          this.add(textField1, null);

 

          textArea1.setBounds(new Rectangle(10, 10, 303, 233));

          textArea1.setBackground(Color.lightGray);

          this.add(textArea1, null);

          // -- End edit controls

 

          // -- Begin menus section

          popupMenu1.setLabel("User menu");

          menuItem1.setLabel("Ignore user");

          menuItem1.setActionCommand ("BAN");

          menuItem1.addActionListener (this);

          menuItem2.setLabel("Deignore user");

          menuItem2.setActionCommand ("UNBAN");

          menuItem2.addActionListener (this);

          popupMenu1.add(menuItem1);

          popupMenu1.addSeparator();

          popupMenu1.add(menuItem2);

          // -- End menus section

 

          list1.setBounds(new Rectangle(316, 11, 104, 233));

          list1.add (popupMenu1);

          list1.addActionListener (this);

          list1.addMouseListener (this);

          list1.setBackground(Color.lightGray);

          this.add (popupMenu1);

          this.add(list1, null);

 

          this.setBackground(Color.cyan);

     }

 

     /**

      * Method sends aMessage to server through ChatClient.

      * @param aMessage

      */

     public void sendMessage (String aMessage) {

          cl.getOutput().println (aMessage);

          cl.getOutput().flush();

     }

 

     /**

      * Method handles ActionEvent event, registered by "this" Action listener.

      * @param ae - ActionEvent which we used to indicate "sender".

      */

     public void actionPerformed (ActionEvent ae) {

 

          if (ae.getSource().equals(textField1)) {

// catch ActionEvents coming from textField1

               sendButtonPressed();

          } else if (ae.getSource().equals(connectButton)) {

// catch ActionEvents coming connect button from textField1

               if (!isConnected) {

                    addSystemMessage("Connecting...");

                    isConnected = cl.connect();

               } else {

                    addSystemMessage("Already connected.");

               }

          } else if (ae.getSource().equals(sendButton)) {

// catch ActionEvents coming send button from textField1

               sendButtonPressed();

          } else if (ae.getSource().equals(menuItem1)) {

// catch ActionEvents comming from popupMenu->menuItem1->"Ignore"

               String selectedUser = list1.getSelectedItem();

               deniedUsers.addElement (selectedUser);

               addSystemMessage("User added to ban list.");

          } else if (ae.getSource().equals(menuItem2)) {

// catch ActionEvents comming from popupMenu->menuItem1->"Deignore"

               String selectedUser = list1.getSelectedItem();

               if (!deniedUsers.removeElement (selectedUser))

                    addSystemMessage("No such user in ban list.");

               else

                    addSystemMessage("User removed from ban list.");

          } else if (ae.getSource().equals(clearButton)) {

// catch ActionEvents comming from clear button

               textArea1.setText("");

          } else if (ae.getSource().equals(disconnectButton)) {

// catch ActionEvents comming from disconnect button

               cl.disconnect();

          } else if (ae.getSource().equals(exitButton)) {

// catch ActionEvents comming from exit button

               System.exit(0);

          }

     }

 

     private void sendButtonPressed() {

          if (!isConnected) {

               textArea1.append("Please connect first.\n");

               return;

          }

          String text = textField1.getText();

          if (text.equals(""))

               return;

          sendMessage (text);

          textField1.setText ("");

     }

 

     public void mouseClicked(MouseEvent e) {}

     public void mouseReleased(MouseEvent e) {}

     public void mouseEntered(MouseEvent e) {}

     public void mouseExited(MouseEvent e) {}

 

     /**

      * Method handles mousePressed event, registered by "this" MouseListener.

      * @param e MouseEvent

      */

     public void mousePressed(MouseEvent e) {

          // register when user pressed right mouse button

          // - e.getModifiers()==e.BUTTON3_MASK -

          // and when is "mouse down" - e.MOUSE_PRESSED==501.

          if ((e.getModifiers()==e.BUTTON3_MASK)&&(e.MOUSE_PRESSED==501)) {

               popupMenu1.show (list1, e.getX(), e.getY());

          }

     }

 

}

 
 

/**

 * Chat applet client for Nakov Chat Server.

 * Author: Nikolay Nedyalkov, 2002

 *

 * ChatClient class handles the communication with the chat server.

 */

import java.io.*;

import java.net.*;

import java.awt.*;

import java.awt.event.*;

import java.applet.*;

import java.util.Hashtable;

 

public class ChatClient

{

     public static final int SERVER_PORT = 2002;

 

     private Socket m_Socket = null;

     private BufferedReader in = null;

     private PrintWriter out = null;

     private ChatApplet m_Applet;

 

     /**

      * Constructor initialize ChatClient and sets ChatApplet refferences.

      */

     public ChatClient (ChatApplet anApplet) {

          this.m_Applet = anApplet;

     }

 

     /**

      * Method is called from ChatApplet.

      * @return PrintWriter reference to server connection.

      */

     public PrintWriter getOutput () {

          return out;

     }

 

     /**

      * Method is called from ChatApplet.

      * @return BufferedReader reference to server connection.

      */

     public BufferedReader getInput () {

          return in;

     }

 

     /**

      * Method is called from ChatApplet to establish connection to NakovChatServer.

      * In case of the applet is started locally from a file (not from a web server),

      * "localhost" is used as taget server, otherwise getCodeBase().getHost() is used.

      */

     public boolean connect () {

          boolean successfull = true;

          String serverHost = m_Applet.getCodeBase().getHost();

          if (serverHost.length()==0) {

               m_Applet.addSystemMessage("Warning: Applet is loaded from a local file,");

               m_Applet.addSystemMessage("not from a web server. Web browser's security");

               m_Applet.addSystemMessage("will probably disable socket connections.");

               serverHost = "localhost";

          }

          try {

               m_Socket = new Socket(serverHost, SERVER_PORT);

               in = new BufferedReader(

                    new InputStreamReader(m_Socket.getInputStream()));

               out = new PrintWriter(

                    new OutputStreamWriter(m_Socket.getOutputStream()));

               m_Applet.addSystemMessage("Connected to server " +

                  serverHost + ":" + SERVER_PORT);

          } catch (SecurityException se) {

               m_Applet.addSystemMessage("Security policy does not allow " +

                    "connection to " + serverHost + ":" + SERVER_PORT);

               successfull = false;

          } catch (IOException e) {

               m_Applet.addSystemMessage("Can not establish connection to " +

                    serverHost + ":" + SERVER_PORT);

               successfull = false;

          }

 

          // Create and start Listener thread

          Listener listener = new Listener(m_Applet, in);

          listener.setDaemon(true);

          listener.start();

 

          return successfull;

     }

 

     public void disconnect() {

          if (!m_Applet.getConnected()) {

               m_Applet.addSystemMessage("Can not disconnect. Not connected.");

               return;

          }

          m_Applet.setConnected(false);

          try {

               m_Socket.close();

          } catch (IOException ioe) {

          }

          m_Applet.addSystemMessage("Disconnected.");

     }

 

     /**

      * Listener class - thread is used for receiving data that comes from

      * the server and then "forward" it to ChatApplet.

      */

     class Listener extends Thread

     {

          private BufferedReader mIn;

          private ChatApplet mCA;

 

          /**

           * Constructor initiliaze InputStream, and ChatApplet reference

           * @param aCA - ChatApplet reference

           * @param aIn - InputStream from server connection

           */

          public Listener (ChatApplet aCA, BufferedReader aIn) {

               mCA = aCA;

               mIn  = aIn;

          }

 

          public void run() {

               try {

                    while (!isInterrupted()) {

                         String message = mIn.readLine();

                         int colon2index = message.indexOf(":",message.indexOf(":")+1);

                         String user = message.substring(0, colon2index-1);

                         mCA.addText (message, user);

                         mCA.addUser (user);

                    }

               } catch (Exception ioe) {

                    if (m_Applet.getConnected())

                         m_Applet.addSystemMessage("Communication error.");

               }

               m_Applet.setConnected(false);

          }

     }

}

 

NakovChatServer å äîñòúïåí îò ëåêöèÿ 1.9 (Ðàçðàáîòêà íà chat êëèåíò/ñúðâúð).

Running the Applet

Çà äà èçïúëíèì chat àïëåòà å íåîáõîäèìî äà íàïðàâèì HTML ñòðàíèöà, êîÿòî ãî ñúäúðæà êàòî îáåêò. Íàïðèìåð ìîæåì äà èçïîëçâàìå ñëåäíàòà (ChatApplet.html):

<html>

 

<head>

     <meta http-equiv="Content-Type" content="text/html; charset=windows-1251">

     <title>Chat Applet</title>

</head>

 

<body>

 

     ChatApplet will appear below in a Java enabled browser.<br>

 

     <applet

       codebase = "."

       code     = "ChatApplet.class"

       name     = "TestApplet"

       width    = "430"

       height   = "300"

       hspace   = "0"

       vspace   = "0"

       align    = "middle"

     >

     </applet>

    

</body>

 

</html>

Çà äà èçïúëíèì àïëeòà â AppletViewer å äîñòàòú÷íî äà ãî êîìïèëèðàìå è äà ãî ñòàðòèðàìå ñ ïðîãðàìàòà appletviewer, íàìèðàùà ñå â binäèðåêòîðèÿòà íà íàøàòà èíñòàëàöèÿ íà JDK:

C:\Projects\ChatApplet> set PATH=%PATH%;C:\jdk1.3.1\bin

C:\Projects\ChatApplet> javac *.java

C:\Projects\ChatApplet> appletviewer ChatApplet.html

Çà äà ãî èçïúëíèì, îáà÷å â íàøèÿ web-áðàóçúð (íàïðèìåð â Internet Explorer 5.0), å íåîáõîäèìî äà ñòàðòèðàìå íÿêàêúâ web-ñúðâúð è äà ïîèñêàìå ñòðàíèöàòà ñ àïëåòà îò òîçè ñúðâúð ÷ðåç URL-òî, îò êîåòî òÿ å äîñòúïíà.  äèðåêòîðèÿòà, â êîÿòî ñå íàìèðà òàçè ñòðàíèöà, òðÿáâà äà ñå íàìèðàò è âñè÷êè .classôàéëîâå, íåîáõîäèìè çà ðàáîòàòà íà àïëåòà. Òðÿáâà äà ñìå íàÿñíî, ÷å àêî îòâîðèì ëîêàëíî êàòî ôàéë (íå êàòî URL)ñòðàíèöàòà ChatApplet.html, àïëåòúò ùå ñå ñòàðòèðà, íî íÿìà äà èìà ïðàâî äà îòâàðÿ ñîêåòè. Òîâà å òàêà îò ñúîáðàæåíèÿ çà ñèãóðíîñòè å ñúâñåì àäåêâàòíà ïîëèòèêà íà çàùèòà, êîÿòî web-áðàóçúðèòå ïðèëàãàò. Êîãàòî àïëåòúò å ñòàðòèðàí îò ñòðàíèöà, çàðåäåíà îò ëîêàëåí ôàéë, getCodeBase().getHost()âðúùà ïðàçåí íèçè àïëåòúò íÿìà ïðàâî äà îòâàðÿ íèêàêâè ñîêåòè. Êîãàòî àïëåòúò å ñòàðòèðàí îò ñòðàíèöà, çàðåäåíà îò íÿêîé web-ñúðâúð, getCodeBase().getHost() âðúùà èìåòî íà òîçè ñúðâúð èëè IP àäðåñà ìó è àïëåòúò èìà ïðàâî äà îòâàðÿ ñîêåòè êúì íåãî. Çàòîâà,çà äà òåñòâàìå àïëåòè â åñòåñòâåíàòà èì ñðåäà (web-áðàóçúðúò), íè å íåîáõîäèì äîñòúï äî íÿêàêúâ web-ñúðâúð, íà êúäåòî äà ãè ïóáëèêóâàìå.