I need help with this Java Assignment. Thanks Chat Server Project with a GUI for
ID: 3839860 • Letter: I
Question
I need help with this Java Assignment. Thanks
Chat Server Project with a GUI for the Clients create a chat server-client pair with a GUI that will allow users to send private plain-text messages, and private encrypted messages to a u ser of their choice as w ell as group messages to all connected clients REQUIREMENTS Create a group chat server that clients will connect to The default behavior when a message is sent from a client is that it goes through the server and the server sends the message to ALL connected recipients The client should have the option of sending a private message, by specifying who they want to send a message to The client should be able to send an encrypted private message using a by specifying who they want to send a message to and that they intend to encrypt it. (Messages get encrypted on the originating client's end and decrypted on the receiving client's end)Explanation / Answer
The given code contains five classes that you can put in a directory on your IDE and then run the code it will work definetly.
There are 5 classes available in the code and the names are listed please check below:
ChatMessage.java
import java.io.*;
public class ChatMessaging implements Serializable {
protected static final long serialVersionUID = 11112122200L;
// The different types of message sent by the ClientSide
// WHOISIN to receive the list of the users connected
// MESSAGE an ordinary message
// LOGOUT to disconnect from the ServerSide
static final int WHOISIN = 0, MESSAGE = 1, LOGOUT = 2;
private int type;
private String message;
// constructor
ChatMessaging(int type, String message) {
this.type = type;
this.message = message;
}
// getters
int getType() {
return type;
}
String getMessage() {
return message;
}
}
ServerSide.java
import java.io.*;
import java.net.*;
import java.text.SimpleDateFormat;
import java.util.*;
/*
* The ServerSide that can be run both as a console application or a GUI
*/
public class ServerSide {
// a unique ID for each connection
private static int uniqueId;
// an ArrayList to keep the list of the ClientSide
private ArrayList<ClientThread> al;
// if I am in a GUI
private ServerGUICode sg;
// to display time
private SimpleDateFormat sdf;
// the port number to listen for connection
private int port;
// the boolean that will be turned of to stop the ServerSide
private boolean keepGoing;
/*
* ServerSide constructor that receive the port to listen to for connection as parameter
* in console
*/
public ServerSide(int port) {
this(port, null);
}
public ServerSide(int port, ServerGUICode sg) {
// GUI or not
this.sg = sg;
// the port
this.port = port;
// to display hh:mm:ss
sdf = new SimpleDateFormat("HH:mm:ss");
// ArrayList for the ClientSide list
al = new ArrayList<ClientThread>();
}
public void start() {
keepGoing = true;
/* create socket ServerSide and wait for connection requests */
try
{
// the socket used by the ServerSide
ServerSocket serverSocket = new ServerSocket(port);
// infinite loop to wait for connections
while(keepGoing)
{
// format message saying we are waiting
display("ServerSide waiting for Clients on port " + port + ".");
Socket socket = serverSocket.accept(); // accept connection
// if I was asked to stop
if(!keepGoing)
break;
ClientThread t = new ClientThread(socket); // make a thread of it
al.add(t);// save it in the ArrayList
t.start();
}
// I was asked to stop
try {
serverSocket.close();
for(int i = 0; i < al.size(); ++i) {
ClientThread tc = al.get(i);
try {
tc.sInput.close();
tc.sOutput.close();
tc.socket.close();
}
catch(IOException ioE) {
// not much I can do
}
}
}
catch(Exception e) {
display("Exception closing the ServerSide and clients: " + e);
}
}
// something went bad
catch (IOException e) {
String msg = sdf.format(new Date()) + " Exception on new ServerSocket: " + e + " ";
display(msg);
}
}
/*
* For the GUI to stop the ServerSide
*/
protected void stop() {
keepGoing = false;
// connect to myself as ClientSide to exit statement
// Socket socket = serverSocket.accept();
try {
new Socket("localhost", port);
}
catch(Exception e) {
// nothing I can really do
}
}
/*
* Display an event (not a message) to the console or the GUI
*/
private void display(String msg) {
String time = sdf.format(new Date()) + " " + msg;
if(sg == null)
System.out.println(time);
else
sg.appendEvent(time + " ");
}
/*
* to broadcast a message to all Clients
*/
private synchronized void broadcast(String message) {
// add HH:mm:ss and to the message
String time = sdf.format(new Date());
String messageLf = time + " " + message + " ";
// display message on console or GUI
if(sg == null)
System.out.print(messageLf);
else
sg.appendRoom(messageLf); // append in the room window
// we loop in reverse order in case we would have to remove a ClientSide
// because it has disconnected
for(int i = al.size(); --i >= 0;) {
ClientThread ct = al.get(i);
// try to write to the ClientSide if it fails remove it from the list
if(!ct.writeMsg(messageLf)) {
al.remove(i);
display("Disconnected ClientSide " + ct.username + " removed from list.");
}
}
}
// for a ClientSide who logoff using the LOGOUT message
synchronized void remove(int id) {
// scan the array list until we found the Id
for(int i = 0; i < al.size(); ++i) {
ClientThread ct = al.get(i);
// found it
if(ct.id == id) {
al.remove(i);
return;
}
}
}
/*
* To run as a console application just open a console window and:
* > java ServerSide
* > java ServerSide portNumber
* If the port number is not specified 1500 is used
*/
public static void main(String[] args) {
// start ServerSide on port 1500 unless a PortNumber is specified
int portNumber = 1500;
switch(args.length) {
case 1:
try {
portNumber = Integer.parseInt(args[0]);
}
catch(Exception e) {
System.out.println("Invalid port number.");
System.out.println("Usage is: > java ServerSide [portNumber]");
return;
}
case 0:
break;
default:
System.out.println("Usage is: > java ServerSide [portNumber]");
return;
}
// create a ServerSide object and start it
ServerSide ServerSide = new ServerSide(portNumber);
ServerSide.start();
}
/** One instance of this thread will run for each ClientSide */
class ClientThread extends Thread {
// the socket where to listen/talk
Socket socket;
ObjectInputStream sInput;
ObjectOutputStream sOutput;
// my unique id (easier for deconnection)
int id;
// the Username of the ClientSide
String username;
// the only type of message a will receive
ChatMessaging cm;
// the date I connect
String date;
// Constructore
ClientThread(Socket socket) {
// a unique id
id = ++uniqueId;
this.socket = socket;
/* Creating both Data Stream */
System.out.println("Thread trying to create Object Input/Output Streams");
try
{
// create output first
sOutput = new ObjectOutputStream(socket.getOutputStream());
sInput = new ObjectInputStream(socket.getInputStream());
// read the username
username = (String) sInput.readObject();
display(username + " just connected.");
}
catch (IOException e) {
display("Exception creating new Input/output Streams: " + e);
return;
}
// have to catch ClassNotFoundException
// but I read a String, I am sure it will work
catch (ClassNotFoundException e) {
}
date = new Date().toString() + " ";
}
// what will run forever
public void run() {
// to loop until LOGOUT
boolean keepGoing = true;
while(keepGoing) {
// read a String (which is an object)
try {
cm = (ChatMessaging) sInput.readObject();
}
catch (IOException e) {
display(username + " Exception reading Streams: " + e);
break;
}
catch(ClassNotFoundException e2) {
break;
}
// the messaage part of the ChatMessaging
String message = cm.getMessage();
// Switch on the type of message receive
switch(cm.getType()) {
case ChatMessaging.MESSAGE:
broadcast(username + ": " + message);
break;
case ChatMessaging.LOGOUT:
display(username + " disconnected with a LOGOUT message.");
keepGoing = false;
break;
case ChatMessaging.WHOISIN:
writeMsg("List of the users connected at " + sdf.format(new Date()) + " ");
// scan al the users connected
for(int i = 0; i < al.size(); ++i) {
ClientThread ct = al.get(i);
writeMsg((i+1) + ") " + ct.username + " since " + ct.date);
}
break;
}
}
// remove myself from the arrayList containing the list of the
// connected Clients
remove(id);
close();
}
// try to close everything
private void close() {
// try to close the connection
try {
if(sOutput != null) sOutput.close();
}
catch(Exception e) {}
try {
if(sInput != null) sInput.close();
}
catch(Exception e) {};
try {
if(socket != null) socket.close();
}
catch (Exception e) {}
}
/*
* Write a String to the ClientSide output stream
*/
private boolean writeMsg(String msg) {
// if ClientSide is still connected send the message to it
if(!socket.isConnected()) {
close();
return false;
}
// write the message to the stream
try {
sOutput.writeObject(msg);
}
// if an error occurs, do not abort just inform the user
catch(IOException e) {
display("Error sending message to " + username);
display(e.toString());
}
return true;
}
}
}
ClientSide.java
import java.net.*;
import java.io.*;
import java.util.*;
/*
* The ClientSide that can be run both as a console or a GUI
*/
public class ClientSide {
// for I/O
private ObjectInputStream sInput;// to read from the socket
private ObjectOutputStream sOutput;// to write on the socket
private Socket socket;
// if I use a GUI or not
private ClientGUICode cg;
// the ServerSide, the port and the username
private String ServerSide, username;
private int port;
/*
* Constructor called by console mode
* ServerSide: the ServerSide address
* port: the port number
* username: the username
*/
ClientSide(String ServerSide, int port, String username) {
// which calls the common constructor with the GUI set to null
this(ServerSide, port, username, null);
}
/*
* Constructor call when used from a GUI
* in console mode the ClienGUI parameter is null
*/
ClientSide(String ServerSide, int port, String username, ClientGUICode cg) {
this.ServerSide = ServerSide;
this.port = port;
this.username = username;
// save if we are in GUI mode or not
this.cg = cg;
}
/*
* To start the dialog
*/
public boolean start() {
// try to connect to the ServerSide
try {
socket = new Socket(ServerSide, port);
}
// if it failed not much I can so
catch(Exception ec) {
display("Error connectiong to ServerSide:" + ec);
return false;
}
String msg = "Connection accepted " + socket.getInetAddress() + ":" + socket.getPort();
display(msg);
/* Creating both Data Stream */
try
{
sInput = new ObjectInputStream(socket.getInputStream());
sOutput = new ObjectOutputStream(socket.getOutputStream());
}
catch (IOException eIO) {
display("Exception creating new Input/output Streams: " + eIO);
return false;
}
// creates the Thread to listen from the ServerSide
new ListenFromServer().start();
// Send our username to the ServerSide this is the only message that we
// will send as a String. All other messages will be ChatMessaging objects
try
{
sOutput.writeObject(username);
}
catch (IOException eIO) {
display("Exception doing login : " + eIO);
disconnect();
return false;
}
// success we inform the caller that it worked
return true;
}
/*
* To send a message to the console or the GUI
*/
private void display(String msg) {
if(cg == null)
System.out.println(msg); // println in console mode
else
cg.append(msg + " ");// append to the ClientGUICode JTextArea (or whatever)
}
/*
* To send a message to the ServerSide
*/
void sendMessage(ChatMessaging msg) {
try {
sOutput.writeObject(msg);
}
catch(IOException e) {
display("Exception writing to ServerSide: " + e);
}
}
/*
* When something goes wrong
* Close the Input/Output streams and disconnect not much to do in the catch clause
*/
private void disconnect() {
try {
if(sInput != null) sInput.close();
}
catch(Exception e) {} // not much else I can do
try {
if(sOutput != null) sOutput.close();
}
catch(Exception e) {} // not much else I can do
try{
if(socket != null) socket.close();
}
catch(Exception e) {} // not much else I can do
// inform the GUI
if(cg != null)
cg.connectionFailed();
}
/*
* To start the ClientSide in console mode use one of the following command
* > java ClientSide
* > java ClientSide username
* > java ClientSide username portNumber
* > java ClientSide username portNumber serverAddress
* at the console prompt
* If the portNumber is not specified 1500 is used
* If the serverAddress is not specified "localHost" is used
* If the username is not specified "Anonymous" is used
* > java ClientSide
* is equivalent to
* > java ClientSide Anonymous 1500 localhost
* are eqquivalent
*
* In console mode, if an error occurs the program simply stops
* when a GUI id used, the GUI is informed of the disconnection
*/
public static void main(String[] args) {
// default values
int portNumber = 1500;
String serverAddress = "localhost";
String userName = "Anonymous";
// depending of the number of arguments provided we fall through
switch(args.length) {
// > javac ClientSide username portNumber serverAddr
case 3:
serverAddress = args[2];
// > javac ClientSide username portNumber
case 2:
try {
portNumber = Integer.parseInt(args[1]);
}
catch(Exception e) {
System.out.println("Invalid port number.");
System.out.println("Usage is: > java ClientSide [username] [portNumber] [serverAddress]");
return;
}
// > javac ClientSide username
case 1:
userName = args[0];
// > java ClientSide
case 0:
break;
// invalid number of arguments
default:
System.out.println("Usage is: > java ClientSide [username] [portNumber] {serverAddress]");
return;
}
// create the ClientSide object
ClientSide ClientSide = new ClientSide(serverAddress, portNumber, userName);
// test if we can start the connection to the ServerSide
// if it failed nothing we can do
if(!ClientSide.start())
return;
// wait for messages from user
Scanner scan = new Scanner(System.in);
// loop forever for message from the user
while(true) {
System.out.print("> ");
// read message from user
String msg = scan.nextLine();
// logout if message is LOGOUT
if(msg.equalsIgnoreCase("LOGOUT")) {
ClientSide.sendMessage(new ChatMessaging(ChatMessaging.LOGOUT, ""));
// break to do the disconnect
break;
}
// message WhoIsIn
else if(msg.equalsIgnoreCase("WHOISIN")) {
ClientSide.sendMessage(new ChatMessaging(ChatMessaging.WHOISIN, ""));
}
else {// default to ordinary message
ClientSide.sendMessage(new ChatMessaging(ChatMessaging.MESSAGE, msg));
}
}
// done disconnect
ClientSide.disconnect();
}
/*
* a class that waits for the message from the ServerSide and append them to the JTextArea
* if we have a GUI or simply System.out.println() it in console mode
*/
class ListenFromServer extends Thread {
public void run() {
while(true) {
try {
String msg = (String) sInput.readObject();
// if console mode print the message and add back the prompt
if(cg == null) {
System.out.println(msg);
System.out.print("> ");
}
else {
cg.append(msg);
}
}
catch(IOException e) {
display("ServerSide has close the connection: " + e);
if(cg != null)
cg.connectionFailed();
break;
}
// can't happen with a String object but need the catch anyhow
catch(ClassNotFoundException e2) {
}
}
}
}
}
ServerGUICode.java
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
/*
* The ServerSide as a GUI
*/
public class ServerGUICode extends JFrame implements ActionListener, WindowListener {
private static final long serialVersionUID = 1L;
// the stop and start buttons
private JButton stopStart;
// JTextArea for the chat room and the events
private JTextArea chat, event;
// The port number
private JTextField tPortNumber;
// my ServerSide
private ServerSide ServerSide;
// ServerSide constructor that receive the port to listen to for connection as parameter
ServerGUICode(int port) {
super("Chat ServerSide");
ServerSide = null;
// in the NorthPanel the PortNumber the Start and Stop buttons
JPanel north = new JPanel();
north.add(new JLabel("Port number: "));
tPortNumber = new JTextField(" " + port);
north.add(tPortNumber);
// to stop or start the ServerSide, we start with "Start"
stopStart = new JButton("Start");
stopStart.addActionListener(this);
north.add(stopStart);
add(north, BorderLayout.NORTH);
// the event and chat room
JPanel center = new JPanel(new GridLayout(2,1));
chat = new JTextArea(80,80);
chat.setEditable(false);
appendRoom("Chat room. ");
center.add(new JScrollPane(chat));
event = new JTextArea(80,80);
event.setEditable(false);
appendEvent("Events log. ");
center.add(new JScrollPane(event));
add(center);
// need to be informed when the user click the close button on the frame
addWindowListener(this);
setSize(400, 600);
setVisible(true);
}
// append message to the two JTextArea
// position at the end
void appendRoom(String str) {
chat.append(str);
chat.setCaretPosition(chat.getText().length() - 1);
}
void appendEvent(String str) {
event.append(str);
event.setCaretPosition(chat.getText().length() - 1);
}
// start or stop where clicked
public void actionPerformed(ActionEvent e) {
// if running we have to stop
if(ServerSide != null) {
ServerSide.stop();
ServerSide = null;
tPortNumber.setEditable(true);
stopStart.setText("Start");
return;
}
// OK start the ServerSide
int port;
try {
port = Integer.parseInt(tPortNumber.getText().trim());
}
catch(Exception er) {
appendEvent("Invalid port number");
return;
}
// ceate a new ServerSide
ServerSide = new ServerSide(port, this);
// and start it as a thread
new ServerRunning().start();
stopStart.setText("Stop");
tPortNumber.setEditable(false);
}
// entry point to start the ServerSide
public static void main(String[] arg) {
// start ServerSide default port 1500
new ServerGUICode(1500);
}
/*
* If the user click the X button to close the application
* I need to close the connection with the ServerSide to free the port
*/
public void windowClosing(WindowEvent e) {
// if my ServerSide exist
if(ServerSide != null) {
try {
ServerSide.stop();// ask the ServerSide to close the conection
}
catch(Exception eClose) {
}
ServerSide = null;
}
// dispose the frame
dispose();
System.exit(0);
}
// I can ignore the other WindowListener method
public void windowClosed(WindowEvent e) {}
public void windowOpened(WindowEvent e) {}
public void windowIconified(WindowEvent e) {}
public void windowDeiconified(WindowEvent e) {}
public void windowActivated(WindowEvent e) {}
public void windowDeactivated(WindowEvent e) {}
/*
* A thread to run the ServerSide
*/
class ServerRunning extends Thread {
public void run() {
ServerSide.start(); // should execute until if fails
// the ServerSide failed
stopStart.setText("Start");
tPortNumber.setEditable(true);
appendEvent("ServerSide crashed ");
ServerSide = null;
}
}
}
ClientGUICode.java
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
/*
* The ClientSide with its GUI
*/
public class ClientGUICode extends JFrame implements ActionListener {
private static final long serialVersionUID = 1L;
// will first hold "Username:", later on "Enter message"
private JLabel label;
// to hold the Username and later on the messages
private JTextField tf;
// to hold the ServerSide address an the port number
private JTextField tfServer, tfPort;
// to Logout and get the list of the users
private JButton login, logout, whoIsIn;
// for the chat room
private JTextArea ta;
// if it is for connection
private boolean connected;
// the ClientSide object
private ClientSide ClientSide;
// the default port number
private int defaultPort;
private String defaultHost;
// Constructor connection receiving a socket number
ClientGUICode(String host, int port) {
super("Chat ClientSide");
defaultPort = port;
defaultHost = host;
// The NorthPanel with:
JPanel northPanel = new JPanel(new GridLayout(3,1));
// the ServerSide name anmd the port number
JPanel serverAndPort = new JPanel(new GridLayout(1,5, 1, 3));
// the two JTextField with default value for ServerSide address and port number
tfServer = new JTextField(host);
tfPort = new JTextField("" + port);
tfPort.setHorizontalAlignment(SwingConstants.RIGHT);
serverAndPort.add(new JLabel("ServerSide Address: "));
serverAndPort.add(tfServer);
serverAndPort.add(new JLabel("Port Number: "));
serverAndPort.add(tfPort);
serverAndPort.add(new JLabel(""));
// adds the ServerSide an port field to the GUI
northPanel.add(serverAndPort);
// the Label and the TextField
label = new JLabel("Enter your username below", SwingConstants.CENTER);
northPanel.add(label);
tf = new JTextField("Anonymous");
tf.setBackground(Color.WHITE);
northPanel.add(tf);
add(northPanel, BorderLayout.NORTH);
// The CenterPanel which is the chat room
ta = new JTextArea("Welcome to the Chat room ", 80, 80);
JPanel centerPanel = new JPanel(new GridLayout(1,1));
centerPanel.add(new JScrollPane(ta));
ta.setEditable(false);
add(centerPanel, BorderLayout.CENTER);
// the 3 buttons
login = new JButton("Login");
login.addActionListener(this);
logout = new JButton("Logout");
logout.addActionListener(this);
logout.setEnabled(false);// you have to login before being able to logout
whoIsIn = new JButton("Who is in");
whoIsIn.addActionListener(this);
whoIsIn.setEnabled(false);// you have to login before being able to Who is in
JPanel southPanel = new JPanel();
southPanel.add(login);
southPanel.add(logout);
southPanel.add(whoIsIn);
add(southPanel, BorderLayout.SOUTH);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(600, 600);
setVisible(true);
tf.requestFocus();
}
// called by the ClientSide to append text in the TextArea
void append(String str) {
ta.append(str);
ta.setCaretPosition(ta.getText().length() - 1);
}
// called by the GUI is the connection failed
// we reset our buttons, label, textfield
void connectionFailed() {
login.setEnabled(true);
logout.setEnabled(false);
whoIsIn.setEnabled(false);
label.setText("Enter your username below");
tf.setText("Anonymous");
// reset port number and host name as a construction time
tfPort.setText("" + defaultPort);
tfServer.setText(defaultHost);
// let the user change them
tfServer.setEditable(false);
tfPort.setEditable(false);
// don't react to a <CR> after the username
tf.removeActionListener(this);
connected = false;
}
/*
* Button or JTextField clicked
*/
public void actionPerformed(ActionEvent e) {
Object o = e.getSource();
// if it is the Logout button
if(o == logout) {
ClientSide.sendMessage(new ChatMessaging(ChatMessaging.LOGOUT, ""));
return;
}
// if it the who is in button
if(o == whoIsIn) {
ClientSide.sendMessage(new ChatMessaging(ChatMessaging.WHOISIN, ""));
return;
}
// ok it is coming from the JTextField
if(connected) {
// just have to send the message
ClientSide.sendMessage(new ChatMessaging(ChatMessaging.MESSAGE, tf.getText()));
tf.setText("");
return;
}
if(o == login) {
// ok it is a connection request
String username = tf.getText().trim();
// empty username ignore it
if(username.length() == 0)
return;
// empty serverAddress ignore it
String ServerSide = tfServer.getText().trim();
if(ServerSide.length() == 0)
return;
// empty or invalid port numer, ignore it
String portNumber = tfPort.getText().trim();
if(portNumber.length() == 0)
return;
int port = 0;
try {
port = Integer.parseInt(portNumber);
}
catch(Exception en) {
return; // nothing I can do if port number is not valid
}
// try creating a new ClientSide with GUI
ClientSide = new ClientSide(ServerSide, port, username, this);
// test if we can start the ClientSide
if(!ClientSide.start())
return;
tf.setText("");
label.setText("Enter your message below");
connected = true;
// disable login button
login.setEnabled(false);
// enable the 2 buttons
logout.setEnabled(true);
whoIsIn.setEnabled(true);
// disable the ServerSide and Port JTextField
tfServer.setEditable(false);
tfPort.setEditable(false);
// Action listener for when the user enter a message
tf.addActionListener(this);
}
}
// to start the whole thing the ServerSide
public static void main(String[] args) {
new ClientGUICode("localhost", 1500);
}
}
Theory :
You can start the Server by typing java Server at the console prompt. That will execute it in console mode and the server will wait for connection on port 1500. To use another port pass the port number to use as first parameter to the command java Server 1200 will ask the Server to listen on port 1200.
You can use <CTRL>C to stop the server.