001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one
003 *  or more contributor license agreements.  See the NOTICE file
004 *  distributed with this work for additional information
005 *  regarding copyright ownership.  The ASF licenses this file
006 *  to you under the Apache License, Version 2.0 (the
007 *  "License"); you may not use this file except in compliance
008 *  with the License.  You may obtain a copy of the License at
009 *
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *  Unless required by applicable law or agreed to in writing,
013 *  software distributed under the License is distributed on an
014 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *  KIND, either express or implied.  See the License for the
016 *  specific language governing permissions and limitations
017 *  under the License.
018 *
019 */
020package org.apache.mina.example.chat.client;
021
022import java.awt.BorderLayout;
023import java.awt.Dimension;
024import java.awt.event.ActionEvent;
025import java.awt.event.ActionListener;
026import java.net.InetSocketAddress;
027import java.net.SocketAddress;
028
029import javax.swing.AbstractAction;
030import javax.swing.BorderFactory;
031import javax.swing.Box;
032import javax.swing.BoxLayout;
033import javax.swing.JButton;
034import javax.swing.JFrame;
035import javax.swing.JLabel;
036import javax.swing.JOptionPane;
037import javax.swing.JPanel;
038import javax.swing.JScrollBar;
039import javax.swing.JTextArea;
040import javax.swing.JTextField;
041import javax.swing.border.EmptyBorder;
042
043import org.apache.mina.example.chat.client.SwingChatClientHandler.Callback;
044import org.apache.mina.transport.socket.nio.NioSocketConnector;
045
046/**
047 * Simple chat client based on Swing & MINA that implements the chat protocol.
048 *
049 * @author <a href="http://mina.apache.org">Apache MINA Project</a>
050 */
051public class SwingChatClient extends JFrame implements Callback {
052    private static final long serialVersionUID = 1538675161745436968L;
053
054    private JTextField inputText;
055
056    private JButton loginButton;
057
058    private JButton quitButton;
059
060    private JButton closeButton;
061
062    private JTextField serverField;
063
064    private JTextField nameField;
065
066    private JTextArea area;
067
068    private JScrollBar scroll;
069
070    private ChatClientSupport client;
071
072    private SwingChatClientHandler handler;
073
074    private NioSocketConnector connector;
075
076    public SwingChatClient() {
077        super("Chat Client based on Apache MINA");
078
079        connector = new NioSocketConnector();
080
081        loginButton = new JButton(new LoginAction());
082        loginButton.setText("Connect");
083        quitButton = new JButton(new LogoutAction());
084        quitButton.setText("Disconnect");
085        closeButton = new JButton(new QuitAction());
086        closeButton.setText("Quit");
087        inputText = new JTextField(30);
088        inputText.setAction(new BroadcastAction());
089        area = new JTextArea(10, 50);
090        area.setLineWrap(true);
091        area.setEditable(false);
092        scroll = new JScrollBar();
093        scroll.add(area);
094        nameField = new JTextField(10);
095        nameField.setEditable(false);
096        serverField = new JTextField(10);
097        serverField.setEditable(false);
098
099        JPanel h = new JPanel();
100        h.setLayout(new BoxLayout(h, BoxLayout.LINE_AXIS));
101        h.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
102        JLabel nameLabel = new JLabel("Name: ");
103        JLabel serverLabel = new JLabel("Server: ");
104        h.add(nameLabel);
105        h.add(Box.createRigidArea(new Dimension(10, 0)));
106        h.add(nameField);
107        h.add(Box.createRigidArea(new Dimension(10, 0)));
108        h.add(Box.createHorizontalGlue());
109        h.add(Box.createRigidArea(new Dimension(10, 0)));
110        h.add(serverLabel);
111        h.add(Box.createRigidArea(new Dimension(10, 0)));
112        h.add(serverField);
113
114        JPanel p = new JPanel();
115        p.setLayout(new BoxLayout(p, BoxLayout.LINE_AXIS));
116        p.setBorder(new EmptyBorder(10, 10, 10, 10));
117
118        JPanel left = new JPanel();
119        left.setLayout(new BoxLayout(left, BoxLayout.PAGE_AXIS));
120        left.add(area);
121        left.add(Box.createRigidArea(new Dimension(0, 5)));
122        left.add(Box.createHorizontalGlue());
123        left.add(inputText);
124
125        JPanel right = new JPanel();
126        right.setLayout(new BoxLayout(right, BoxLayout.PAGE_AXIS));
127        right.add(loginButton);
128        right.add(Box.createRigidArea(new Dimension(0, 5)));
129        right.add(quitButton);
130        right.add(Box.createHorizontalGlue());
131        right.add(Box.createRigidArea(new Dimension(0, 25)));
132        right.add(closeButton);
133
134        p.add(left);
135        p.add(Box.createRigidArea(new Dimension(10, 0)));
136        p.add(right);
137
138        getContentPane().add(h, BorderLayout.NORTH);
139        getContentPane().add(p);
140
141        closeButton.addActionListener(new ActionListener() {
142            public void actionPerformed(ActionEvent e) {
143                client.quit();
144                connector.dispose(); 
145                dispose();
146            }
147        });
148        setLoggedOut();
149        setDefaultCloseOperation(EXIT_ON_CLOSE);
150    }
151
152    public class LoginAction extends AbstractAction {
153        private static final long serialVersionUID = 3596719854773863244L;
154
155        public void actionPerformed(ActionEvent e) {
156
157            ConnectDialog dialog = new ConnectDialog(SwingChatClient.this);
158            dialog.pack();
159            dialog.setVisible(true);
160
161            if (dialog.isCancelled()) {
162                return;
163            }
164
165            SocketAddress address = parseSocketAddress(dialog
166                    .getServerAddress());
167            String name = dialog.getUsername();
168
169            handler = new SwingChatClientHandler(SwingChatClient.this);
170            client = new ChatClientSupport(name, handler);
171            nameField.setText(name);
172            serverField.setText(dialog.getServerAddress());
173
174            if (!client.connect(connector, address, dialog.isUseSsl())) {
175                JOptionPane.showMessageDialog(SwingChatClient.this,
176                        "Could not connect to " + dialog.getServerAddress()
177                                + ". ");
178            }
179        }
180    }
181
182    private class LogoutAction extends AbstractAction {
183        private static final long serialVersionUID = 1655297424639924560L;
184
185        public void actionPerformed(ActionEvent e) {
186            try {
187                client.quit();
188                setLoggedOut();
189            } catch (Exception e1) {
190                JOptionPane.showMessageDialog(SwingChatClient.this,
191                        "Session could not be closed.");
192            }
193        }
194    }
195
196    private class BroadcastAction extends AbstractAction {
197        /**
198         *
199         */
200        private static final long serialVersionUID = -6276019615521905411L;
201
202        public void actionPerformed(ActionEvent e) {
203            client.broadcast(inputText.getText());
204            inputText.setText("");
205        }
206    }
207
208    private class QuitAction extends AbstractAction {
209        private static final long serialVersionUID = -6389802816912005370L;
210
211        public void actionPerformed(ActionEvent e) {
212            if (client != null) {
213                client.quit();
214            }
215            SwingChatClient.this.dispose();
216        }
217    }
218
219    private void setLoggedOut() {
220        inputText.setEnabled(false);
221        quitButton.setEnabled(false);
222        loginButton.setEnabled(true);
223    }
224
225    private void setLoggedIn() {
226        area.setText("");
227        inputText.setEnabled(true);
228        quitButton.setEnabled(true);
229        loginButton.setEnabled(false);
230    }
231
232    private void append(String text) {
233        area.append(text);
234    }
235
236    private void notifyError(String message) {
237        JOptionPane.showMessageDialog(this, message);
238    }
239
240    private SocketAddress parseSocketAddress(String s) {
241        s = s.trim();
242        int colonIndex = s.indexOf(":");
243        if (colonIndex > 0) {
244            String host = s.substring(0, colonIndex);
245            int port = parsePort(s.substring(colonIndex + 1));
246            return new InetSocketAddress(host, port);
247        } else {
248            int port = parsePort(s.substring(colonIndex + 1));
249            return new InetSocketAddress(port);
250        }
251    }
252
253    private int parsePort(String s) {
254        try {
255            return Integer.parseInt(s);
256        } catch (NumberFormatException nfe) {
257            throw new IllegalArgumentException("Illegal port number: " + s);
258        }
259    }
260
261    public void connected() {
262    }
263
264    public void disconnected() {
265        append("Connection closed.\n");
266        setLoggedOut();
267    }
268
269    public void error(String message) {
270        notifyError(message + "\n");
271    }
272
273    public void loggedIn() {
274        setLoggedIn();
275        append("You have joined the chat session.\n");
276    }
277
278    public void loggedOut() {
279        append("You have left the chat session.\n");
280        setLoggedOut();
281    }
282
283    public void messageReceived(String message) {
284        append(message + "\n");
285    }
286
287    public static void main(String[] args) {
288        SwingChatClient client = new SwingChatClient();
289        client.pack();
290        client.setVisible(true);
291    }
292}