Ask a Question
Ask Question Login
Corporate Training
  1. Community
  2. Java
  3. Question
Java

What is the significance of java chat rooms?

Asked by Amit Raj Oct 10, 2022 832 views 1 answer
Share

About this question

In an attempt to learn more with Java, I decided to challenge myself by creating a GUI-based, multi-threaded chat room. Currently, you run the Client and it prompts you to either create or join a server based on an IP. Port used is 9000. Any suggestions on how I can improve?


Server.java:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.sql.Timestamp;
import java.util.HashSet;
import java.util.Set;
public class Server extends Thread {
    /**
     * Used to write to all the connected clients.
     */
    private static final Set WRITERS = new HashSet<>();
    /**
     * Used to keep track of all of the names of connected clients.
     */
    private static final Set NAMES = new HashSet<>();
    /**
     * Used to keep track of the current client's ID for logging purposes.
     */
    private static int clientId = 1;
    /**
     * Used when creating a server.
     */
    private final ServerSocket listener;
    public Server(ServerSocket listener) {
        this.listener = listener;
    }
    /**
     * Used to log messages.
     * 
     * @param message
     */
    public static void log(String message) {
        String timestamp = new Timestamp(System.currentTimeMillis()).toString();
        timestamp = timestamp.substring(0, timestamp.length() - 4);
        System.out.println("[" + timestamp + "] " + message);
    }
    /**
     * Returns the ServerSocket listener.
     * 
     * @return
     */
    public ServerSocket getListener() {
        return this.listener;
    }
    @Override
    public void run() {
        if (listener != null) {
            try {
                if (listener.isBound()) {
                    log("Server started on " + (listener.getInetAddress().getHostAddress()) + " and listening on port "
                            + ServerConstants.PORT);
                }
                while (true) {
                    new User(listener.accept(), clientId++).start();
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    listener.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    /**
     * Creates a server and starts accepting inputs.
     * 
     * @param port
     * @throws IOException
     */
    public static Server createServer(int port) throws IOException {
        return new Server(new ServerSocket(port));
    }
    /**
     * This class listens for and sends messages to messages from all clients.
     * 
     * @author ivisc
     *
     */
    private static class User extends Thread {
        private Socket socket;
        private PrintWriter out;
        private BufferedReader in;
        private String address;
        private String name;
        private int id;
        public User(Socket sock, int id) {
            this.socket = sock;
            this.id = id;
            this.address = socket.getInetAddress().getHostAddress();
        }
        @Override
        public void run() {
            try {
                log("Starting connection from " + this.toString());
                // Start up our variables for use with the socket.
                out = new PrintWriter(socket.getOutputStream(), true);
                in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                // Ask for a name
                while (true) {
                    out.println("ENTERNAME");
                    String line = in.readLine();
                    if (line == null) {
                        return;
                    }
                    if (!Filter.filter(line)) {
                        out.println("INVALIDNAME");
                    } else {
                        synchronised (NAMES) {
                            if (!NAMES.contains(line)) {
                                NAMES.add(line);
                                name = line;
                                out.println("NAME ACC");
                                break;
                            }
                        }
                    }
                }
                WRITERS.add(out);
                log("Registering " + this.toString() + " (" + name + ")");
                for (PrintWriter writer : WRITERS) {
                    writer.println("NEWMEM" + name);
                }
                // Now we listen for names
                while (true) {
                    String message = in.readLine();
                    if (message == null) {
                        return;
                    }
                    if (!Filter.filter(message)) {
                        out.println("INVALIDMESSAGE");
                    } else {
                        for (PrintWriter writer : WRITERS) {
                            writer.println("MESSAGE" + name + ": " + message);
                        }
                    }
                }
            } catch (IOException e) {
                log(this.toString() + " is disconnecting...");
            } finally {
                log("Shutting down I/O from " + this.toString() + " (" + id + ")");
                try {
                    out.close();
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        @Override
        public String toString() {
            return address + "(" + id + ")";
        }
    }
}
Client.java:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
@SuppressWarnings("serial")
public class Client extends JFrame {
    private JTextField textField;
    private JTextArea textArea;
    private Socket socket;
    private PrintWriter out;
    private BufferedReader in;
    public Client() {
        textField = new JTextField(40);
        getContentPane().add(textField, BorderLayout.SOUTH);
        textField.setEditable(false);
        textArea = new JTextArea();
        getContentPane().add(textArea, BorderLayout.NORTH);
        textArea.setEditable(false);
        getContentPane().add(new JScrollPane(textArea), BorderLayout.CENTER);
        textField.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                out.println(textField.getText());
                textField.setText("");
            }
        });
        setPreferredSize(new Dimension(800, 600));
        pack();
        setSize(getPreferredSize());
        setLocationRelativeTo(null);
        setVisible(true);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
    public void initVars() throws IOException {
        this.out = new PrintWriter(socket.getOutputStream(), true);
        this.in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    }
    public void connect(String address) {
        try {
            this.socket = new Socket(address, ServerConstants.PORT);
            initVars();
            this.textField.setEditable(true);
            Server.log("Connected to " + address);
            this.setVisible(true);
            while (true) {
                new ServerListener(out, in).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public void connect(Server server) {
        try {
            String address = server.getListener().getInetAddress().getHostAddress();
            this.socket = new Socket(address, ServerConstants.PORT);
            initVars();
            this.textField.setEditable(true);
            Server.log("Connected to " + address);
            this.setVisible(true);
            while (true) {
                new ServerListener(out, in).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        Scanner s = new Scanner(System.in);
        Object[] options = new Object[] { "Start", "Join", "Cancel" };
        int input = JOptionPane.showOptionDialog(null, "Would you like to create or join a server?",
                "Chat Room Selection", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE, null, options,
                options[1]);
        Client client = new Client();
        switch (input) {
            case 0:
                try {
                    Server server = Server.createServer(ServerConstants.PORT);
                    server.start();
                    client.connect(server);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                break;
            case 1:
                String address = JOptionPane.showInputDialog("Please enter server IP");
                if (address != null) {
                    client.connect(address);
                }
                break;
            case 2:
                System.exit(0);
                break;
        }
        s.close();
    }
    private class ServerListener extends Thread {
        private PrintWriter out;
        private BufferedReader in;
        public ServerListener(PrintWriter out, BufferedReader in) {
            this.out = out;
            this.in = in;
        }
        @Override
        public void run() {
            while (true) {
                try {
                    handle(in.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        public void handle(String message) throws IOException {
            System.out.println("handling " + message);
            if (message == null) {
                return;
            }
            System.out.println(message);
            if (message.startsWith("MESSAGE")) {
                message = message.substring(7);
                textArea.append(message + "n");
            } else if (message.startsWith("ENTERNAME")) {
                while (true) {
                    String name = JOptionPane.showInputDialog("Please enter a username");
                    out.println(name);
                    String response = in.readLine();
                    if (response.equals("INVALIDNAME")) {
                        JOptionPane.showMessageDialog(null, "Name does not pass Name Filter", "Invalid Name",
                                JOptionPane.ERROR_MESSAGE);
                    } else {
                        break;
                    }
                }
            } else if (message.startsWith("NEWMEM")) {
                String name = message.substring(6);
                textArea.append(name + " has joined the server.n");
            }
        }
    }
}

There are a few references to ServerConstants.java and Filter.java here, but I won't include them for brevity's sake. Basically, ServerConstants is an abstract interface that just defines the port to use, and Filter is a simple name filter using a list of "bad words" (I believe it's this one that I used).


I know I didn't comment on everything, and adding throws statements might not be best practice, and extending from JFrame is usually not recommended, but, based on everything here, any suggestions?

Your answer

1 Answer

More Java discussions

Learn & Explore

Free tutorials and interview questions from industry experts — learn the skill, then get ready to prove it.

Latest Java Blogs

Guides, tips and career advice on Java from JanBask experts.