My place to Speak!

Information

This article was written on 27 Mar 2010, and is filled under Programming.

Simple Chatting Application using Java RMI

Since so many visitors come to my blog and searching about creating an application using Java RMI, so now I want to make a new one about simple chatting application using java rmi. I hope my codes free of bugs, but it is unbelievable i think.

Before you continue make this application you must make sure that a JDK has been installed on your computer. If you do not have it before please download JDK from Sun website and install it on your computer.

Now let create the program. I will use Java RMI and make 3 classes and one 1 interface.

  1. ChatImpl (class)
  2. ChatServer (class)
  3. RMIClient (class)
  4. Chatting (interface)

We need Chatting Interface to determine what methods that can be invoked by the client. In this interface i will defines 4 methods that can be invoked by the client.

  • sendPublicMessage => send a message from a client to another client.
  • getClientList => get a numbers of user connected to the server.
  • connect => creating a new socket connection to server.
  • disconnect => terminated connection from server.
/*
File Name : Chatting.java
Author : Angga Lingga
*/

import java.rmi.*;
import java.util.*;

public interface Chatting extends Remote
{
	public void sendPublicMessage(String keyword, String username, String message) throws RemoteException;
	public ArrayList getClientList() throws RemoteException;
	public void connect(String username) throws RemoteException;
	public void disconnect(String username) throws RemoteException;
}

After we determine the methods that can be invoked by the client in the Chatting Interface, now we will create a class that implements the Chatting Interface (for creating the server stub).

/*
File Name : ChatImpl.java
Author : Angga Lingga
*/

import java.rmi.*;
import java.rmi.server.*;
import java.util.*;
import java.net.*;

public class ChatImpl extends UnicastRemoteObject implements Chatting
{
	private ChatServer cs;

	public ChatImpl(ChatServer cs) throws RemoteException
	{
		super();
		this.cs = cs;
	}

	public void sendPublicMessage(String keyword, String username, String message) throws RemoteException
	{
		cs.sendPublicMessage(keyword, username, message);
	}

	public ArrayList getClientList() throws RemoteException
	{
		return cs.getClientList();
	}

	public void connect(String username) throws RemoteException
	{
		cs.connect(username);
	}

	public void disconnect(String username) throws RemoteException
	{
		cs.disconnect(username);
	}
}

Now after we create the ChatImpl, we create the server and the client codes.

/*
File Name : ChatServer.java
Author : Angga Lingga
*/

import java.rmi.*;
import java.rmi.server.*;
import java.net.*;
import java.io.*;
import java.util.*;
import javax.swing.JOptionPane;

public class ChatServer
{
	private static HashMap<String, Socket> connectedUser = new HashMap<String, Socket>();
	private static Socket ClientSocket = null;
	private static ServerSocket serverSocket;
	private static String username = null;
	private static PrintWriter output;

	private static final String PUBLICMESSAGE = "PUBLICMESSAGE";
	private static final String ONLINE = "ONLINE";
	private static final String OFFLINE = "OFFLINE";

	public ChatServer()
	{
		try
		{
			ChatImpl csi = new ChatImpl(this);
			Naming.rebind("rmi://localhost:1099/ChatService", csi);
		}
		catch(java.rmi.ConnectException ce)
		{
			JOptionPane.showMessageDialog(null, "Trouble : Please run rmiregistry.", "Connect Exception", JOptionPane.ERROR_MESSAGE);
			System.exit(-1);
		}
		catch (IOException ioe)
		{
			JOptionPane.showMessageDialog(null, "Trouble : Please run rmiregistry.", "Exception", JOptionPane.ERROR_MESSAGE);
			System.exit(-1);
		}
		catch (Exception e)
		{
			JOptionPane.showMessageDialog(null, "Trouble : Please run rmiregistry.", "Exception", JOptionPane.ERROR_MESSAGE);
			System.exit(-1);
		}
	}

	public static void main (String[] args)
	{
		try
		{
			int port = Integer.parseInt(args[0]);
			ChatServer cs = new ChatServer();
			cs.processConnection(port);
		}
		catch (ArrayIndexOutOfBoundsException ae)
		{
			JOptionPane.showMessageDialog(null, "Please insert the port", "ATTENTION", JOptionPane.INFORMATION_MESSAGE);
			System.exit(-1);
		}
	}

	private void processConnection(int port)
	{
		try
		{
			serverSocket = new ServerSocket(port);
			System.out.println("Server is running on port " + port + " .... ");
		}
		catch (IOException ioe)
		{
			JOptionPane.showMessageDialog(null, "Could not listen port " + port, "ERROR", JOptionPane.ERROR_MESSAGE);
			System.exit(-1);
		}

		try
		{
			while (true)
			{
				addClient(serverSocket.accept());
				String username = getUsername();
				sendPublicMessage(PUBLICMESSAGE, "SERVER", "[" + username + "] is now online");
			}
		}
		catch (IOException ioe)
		{
			JOptionPane.showMessageDialog(null, "Could not accept connection.", "ERROR", JOptionPane.ERROR_MESSAGE);
			System.exit(-1);
		}
	}

	public void connect(String username)
	{
		this.username = username;
	}

	public String getUsername()
	{
		return username;
	}

	public ArrayList getClientList()
	{
		ArrayList myUser = new ArrayList();

		Iterator i = connectedUser.keySet().iterator();
		String user = null;

		while(i.hasNext())
		{
			user = i.next().toString();
			myUser.add(user);
		}

		return myUser;
	}

	public void addClient(Socket clientSocket) throws RemoteException
	{
		connectedUser.put(getUsername(), clientSocket);
		sendPublicMessage(ONLINE, getUsername(), "CLIENT");
	}

	public void sendPublicMessage(String keyword, String username, String message) throws RemoteException
	{
		Iterator i = connectedUser.keySet().iterator();
		String user = null;
		while(i.hasNext())
		{
			try
			{
				user = i.next().toString();
				ClientSocket =  connectedUser.get(user);
				output = new PrintWriter(ClientSocket.getOutputStream(), true);
				output.println(keyword + "***" + username + "***" + message);
				output.flush();
			}
			catch(IOException ioe)
			{
				connectedUser.remove(user);
				sendPublicMessage(OFFLINE, user, user + " has been left the conversation");
			}
		}
	}

	public void disconnect(String username) throws RemoteException
	{
		connectedUser.remove(username);
		sendPublicMessage(OFFLINE, username, username + " has been left the conversation");
		sendPublicMessage(PUBLICMESSAGE, "SERVER", username + " has been left the conversation");
	}
}

 

/*
File Name : RMIClient.java
Author : Angga Lingga
*/

import java.rmi.*;
import java.io.*;
import java.net.*;
import java.awt.*;
import java.util.*;
import javax.swing.*;
import java.awt.event.*;
import javax.swing.event.*;

public class RMIClient extends JFrame implements ActionListener, Runnable
{
	private Chatting c;

	private static String ipAddress;
	private int port;
	private BufferedReader in = null;
	private Thread thread;

	private JButton jButtonConnect;
	private JButton jButtonSend;
	private JLabel jLabelUserList;
	private JList jListUser;
	private JScrollPane jScrollPaneListUser;
	private JScrollPane jScrollPaneMessage;
	private JTextArea jTextAreaMessage;
	private JTextField jTextSendMessage;
	private JTextField jTextUserName;

	private Socket socket = null;
	private DefaultListModel listClient;

	private String message;

	private final String SEPARATOR = "\\*\\*\\*";
	private final String PUBLICMESSAGE = "PUBLICMESSAGE";
	private final String ONLINE = "ONLINE";
	private final String OFFLINE = "OFFLINE";

	public RMIClient()
	{
		initComponents();
		thread = new Thread(this);
	}

	@SuppressWarnings("unchecked")
	private void initComponents()
	{
		listClient = new DefaultListModel();
		jScrollPaneMessage = new JScrollPane();
		jTextAreaMessage = new JTextArea();
		jTextUserName = new JTextField();
		jButtonConnect = new JButton();
		jScrollPaneListUser = new JScrollPane();
		jListUser = new JList(listClient);
		jTextSendMessage = new JTextField();
		jButtonSend = new JButton();
		jLabelUserList = new JLabel();

		setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
		setTitle("Chat Client");
		setResizable(false);
		getContentPane().setLayout(null);

		jTextAreaMessage.setColumns(20);
		jTextAreaMessage.setEditable(false);
		jTextAreaMessage.setRows(5);
		jTextAreaMessage.setAutoscrolls(false);
		jScrollPaneMessage.setViewportView(jTextAreaMessage);

		getContentPane().add(jScrollPaneMessage);
		jScrollPaneMessage.setBounds(10, 10, 340, 240);

		jTextUserName.addActionListener(this);
		getContentPane().add(jTextUserName);
		jTextUserName.setBounds(360, 10, 100, 20);

		jButtonConnect.setFont(new java.awt.Font("Times New Roman", 0, 11));
		jButtonConnect.setText("Connect");

		getContentPane().add(jButtonConnect);
		jButtonConnect.setBounds(470, 10, 80, 21);

		jListUser.setToolTipText("List of User");
		jScrollPaneListUser.setViewportView(jListUser);

		getContentPane().add(jScrollPaneListUser);
		jScrollPaneListUser.setBounds(360, 50, 190, 200);

		jTextSendMessage.addActionListener(this);

		getContentPane().add(jTextSendMessage);
		jTextSendMessage.setBounds(10, 260, 340, 30);

		jButtonSend.setFont(new java.awt.Font("Times New Roman", 0, 11));
		jButtonSend.setText("Send");
		jButtonSend.addActionListener(this);

		getContentPane().add(jButtonSend);
		jButtonSend.setBounds(360, 261, 70, 30);

		jLabelUserList.setFont(new java.awt.Font("Arial Black", 0, 11));
		jLabelUserList.setText("User List");
		getContentPane().add(jLabelUserList);
		jLabelUserList.setBounds(360, 30, 55, 17);

		java.awt.Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
		setBounds((screenSize.width-570)/2, (screenSize.height-330)/2, 570, 330);

		jButtonConnect.addActionListener(this);
		jButtonSend.setEnabled(false);
	}

	public static void main(String args[])
	{
		JFrame.setDefaultLookAndFeelDecorated(true);
		try
		{
			RMIClient rm = new RMIClient();
			rm.setIPAddress(args[0]);
			rm.setPort(Integer.parseInt(args[1]));
			rm.setServer(ipAddress);
			rm.setVisible(true);
		}
		catch (ArrayIndexOutOfBoundsException ae)
		{
			JOptionPane.showMessageDialog(null, "Please insert the port", "ATTENTION", JOptionPane.INFORMATION_MESSAGE);
			System.exit(-1);
		}
	}

	private void setIPAddress(String ipAddress)
	{
		this.ipAddress = ipAddress;
	}

	private void setPort(int port)
	{
		this.port = port;
	}

	private String getIPAddress()
	{
		return ipAddress;
	}

	private int getPort()
	{
		return port;
	}

	private void setServer(String ipAddress)
	{
		try
		{
			c = (Chatting) Naming.lookup("rmi://" + ipAddress + "/ChatService");
		}
		catch (MalformedURLException murle)
		{
			System.out.println();
			System.out.println("MalformedURLException");
			System.out.println(murle);
		}
		catch (RemoteException re)
		{
			System.out.println();
			System.out.println("RemoteException");
			System.out.println(re);
		}
		catch (NotBoundException nbe)
		{
			System.out.println();
			System.out.println("NotBoundException");
			System.out.println(nbe);
		}
		catch (Exception e)
		{
			System.out.println(e);
		}
	}

	public void updateMessage(String username, String message) throws RemoteException
	{
		jTextAreaMessage.append(username + " >> " + message + "\n");
	}

	public void run()
	{
		System.out.println(socket);
		try
		{
			in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

			while((message = in.readLine()) != null)
			{
				System.out.println(message);
				String[] fromServer = message.split(SEPARATOR);
				if (fromServer[0].equals(ONLINE) || fromServer[0].equals(OFFLINE))
				{
					updateClient(c.getClientList());
				}
				else if (fromServer[0].equals(PUBLICMESSAGE))
				{
					String sender = fromServer[1];
					String content = fromServer[2];
					updateMessage(sender, content);
				}
			}

			in.close();
			socket.close();
		}
		catch(java.net.UnknownHostException e) {}
		catch(IOException e) {}
	}

	public void updateClient(ArrayList allClientList) throws RemoteException
	{
		listClient.clear();
		int i = 0;
		String username;

		for(i=0; i<allClientList.size(); i++)
		{
			username = allClientList.get(i).toString();
			listClient.addElement(username);
		}
	}

	public void actionPerformed(ActionEvent ae)
	{
		if (ae.getActionCommand().equals("Connect") && !jTextUserName.getText().equals(""))
		{
			try
			{
				System.out.println(jTextUserName.getText());
				c.connect(jTextUserName.getText());
				socket = new Socket(ipAddress, port);
				jTextUserName.setEditable(false);
				jButtonConnect.setText("Disconnect");
				System.out.println("You are connect to server");
				thread.start();
				jButtonSend.setEnabled(true);
			}
			catch (RemoteException re) {}
			catch(java.net.UnknownHostException e)
			{
				JOptionPane.showMessageDialog(null, "Can not connect to server " + ipAddress ,"WARNING", JOptionPane.WARNING_MESSAGE);
				System.exit(-1);
			}
			catch(IOException e)
			{
				JOptionPane.showMessageDialog(null, "The server " + ipAddress + " on port " + port + " is not found!", "ERROR",JOptionPane.ERROR_MESSAGE);
				System.exit(-1);
			}
		}
		else if (ae.getActionCommand().equals("Disconnect"))
		{
			try
			{
				c.disconnect(jTextUserName.getText());
				jTextUserName.setText("");
				jTextUserName.setEditable(true);
				listClient.clear();
				jButtonConnect.setText("Connect");
				thread.interrupt();
			}
			catch (RemoteException re) {}
		}
		else if (ae.getSource() == jButtonSend && !jTextSendMessage.getText().equals(""))
		{
			try
			{
				c.sendPublicMessage(PUBLICMESSAGE, jTextUserName.getText(), jTextSendMessage.getText());
				jTextSendMessage.setText("");
			}
			catch (RemoteException re) {}
		}
	}
}

Now after we make the code. Let run the application.

  1. Open your command prompt(under Windows OS).
  2. Compile all the files >>  javac *.java
  3. Compile the ChatImpl.java (it will create a new stub) >> rmic ChatImpl
  4. Run the RMIRegistry >> rmirgistry
  5. You must make sure that your rmiregistrycommand run successfully. If your command does not run, may this command has not recognized by your system yet. If this command does not run, please follow these instructions below (I use Microsoft Windows Vista):
    • Right click on your My Computer and click ‘Properties‘.
    • Click ‘Advanced system settings‘.
    • You must make sure that you already on the ‘Advanced’ tab. Click ‘Environment Variables‘.
    • On the ‘Systems variables‘ section, find ‘Path‘ item and double click and insert your JDK lib directory location on ‘variable value‘ text box. You must make a separator ‘;‘ (without quotes) before insert it (required).
      My JDK lib directory location: ‘C:\Program Files\Java\jdk1.6.0_10\bin
    • Click OK > OK > OK
  6. Open a new command prompt.
  7. Run the server >> java ChatServer YOUR_AVAILABLE_PORT (ex: java ChatServer 4444)
    I hope the response should be like this >> Server is running on port YOUR_AVAILABLE_PORT
  8. Open a new command prompt.
  9. Run a new client >> java RMIClient SERVER_ADDRESS SERVER_PORT (ex: java RMIClient 127.0.0.1 4444)
  10. Insert your name “angga” and client Connect.
    I hope the server response should be like this >> SERVER >> [angga] is now online
    It show that you have connect to server.
  11. Open a new command prompt again.
  12. Run a new client again >> java RMIClient SERVER_ADDRESS SERVER_PORT (ex: java RMIClient 127.0.0.1 4444)
  13. Insert your name “lingga” and client Connect.
    I hope the server response should be like this >> SERVER >> [lingga] is now online
    It show that you have connect to server.
  14. Now you angga and lingga can chat with one server.

You can download the source codes here.

I have develop a new one chatting application using Java RMI too. This application have many server. It allows one client in the different server can talk each other.

Client Chatting

Client Chatting Process

>> java RMIClient SERVER_ADDRESS SERVER_PORT

29 Comments

  1. Manish
    April 23, 2014

    Hi,
    Thanks for the code.
    I was trying to run the code on different machine but i’m unable to make connections on different machines.
    The code runs very well on localhost but on separate pc’s RMIClient is unable to make connections

  2. Manish
    April 23, 2014

    Hi,
    Thanks for the code.
    I was trying to run the code on different machine but i’m unable to make connections on different machines.
    The code runs very well on localhost but on separate pc’s RMIClient is unable to make connections
    Please troubleshoot the problem asap

    Thanks

  3. Carlos
    July 2, 2014

    Everytime i tried to run this program it asks me for the port

Leave a Reply