Group Chat Example using Java RMI with a Graphical User Interface

The aim of this tutorial is to motivate you for creating a very simple project using Java RMI showing an basic example of a distributed system.

You may need to download Eclipse and Java JDK and get them installed on your machine regardless your operating system ( Windows or Linux ).

There are 4 parts in this tutorial, 1) Server Side + 2) Client Side. 3) Packaging 4) Running the Application. The structures of the projects are shown below:

rmi-chat-gui-19

1) Server Side

 
1 Open Eclipse and create a new Java Project via : File –> New –> Java Project

2 Set the name of the project as : ChatServer

rmi-chat-gui-1

3 Create a new Interface under this project named : ChatServerInt via. Right Click under the project ChatServer–> New–> Interface

rmi-chat-gui-2

4 Type in the following code the interface : ChatServerInt

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

public interface ChatServerInt extends Remote{	
	public boolean login (ChatClientInt a)throws RemoteException ;
	public void publish (String s)throws RemoteException ;
	public Vector getConnected() throws RemoteException ;
}

5 Create a new Interface under this project named : ChatClienInt via. Right Click under the project ChatServer–> New–> Interface. Type the following code for the interface:

import java.rmi.*;

public interface ChatClientInt extends Remote{	
	public void tell (String name)throws RemoteException ;
	public String getName()throws RemoteException ;
}

6 Create a new class named ChatServer under the project. Right Click under the project ChatServer–> New–> Class

rmi-chat-gui-4

7 Type the name of the class as : ChatServer

rmi-chat-gui-5

8 Type the following code for the class ChatServer

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

public class ChatServer  extends UnicastRemoteObject implements ChatServerInt{
	
	private Vector v=new Vector();	
	public ChatServer() throws RemoteException{}
		
	public boolean login(ChatClientInt a) throws RemoteException{	
		System.out.println(a.getName() + "  got connected....");	
		a.tell("You have Connected successfully.");
		publish(a.getName()+ " has just connected.");
		v.add(a);
		return true;		
	}
	
	public void publish(String s) throws RemoteException{
	    System.out.println(s);
		for(int i=0;i<v.size();i++){
		    try{
		    	ChatClientInt tmp=(ChatClientInt)v.get(i);
			tmp.tell(s);
		    }catch(Exception e){
		    	//problem with the client not connected.
		    	//Better to remove it
		    }
		}
	}

	public Vector getConnected() throws RemoteException{
		return v;
	}
}

9 We need to create new class under the project ChatServer named as : StartServer. Type the following code for the class StartServer

import java.rmi.*;
import java.rmi.server.*;
 
public class StartServer {
	public static void main(String[] args) {
		try {
				//System.setSecurityManager(new RMISecurityManager());
			 	java.rmi.registry.LocateRegistry.createRegistry(1099);
			 	
				ChatServerInt b=new ChatServer();	
				Naming.rebind("rmi://192.168.1.102/myabc", b);
				System.out.println("[System] Chat Server is ready.");
			}catch (Exception e) {
					System.out.println("Chat Server failed: " + e);
			}
	}
}
Change the IP address 192.168.1.102 to your IP address. Better not to use localhost

10 Run your server but for the sake only of compiling through clicking the Green play button shown below:

rmi-chat-gui-6

11 Now, You need to open your DOS cmd console ( or unix terminal). Navigate to your workspace BIN folder for the project. The location of your project can be known through clicking: Select the project ChatServer, Right Click -> Properties

rmi-chat-gui-7

12 Copy the location shown on the next window for the project:

rmi-chat-gui-8

13 Within the CMD black window, type in the full location of the bin folder. For example :

cd C:\Users\imed\workspace\ChatServer\bin

Make sure you type YOUR location, not mine. Make sure that you are inside the BIN folder

14 Run the rmic to generate the stub for the remote object ChatServer Run the following command:

rmic ChatServer -> Press Enter

That’s it almost for the Server Side !

2) Client Side

1 Create a new Java Project via : File –> New –> Java Project, set its name as : ChatClientProj

2 Create a new Interface ChatClientInt under the project ChatClientProj with exactly the same code as above.

3 Create a new Interface ChatServerInt under the project ChatClientProj with exactly the same code as above.

4 Create a new Class : ChatClient under the project ChatClientProj, copy and paste the following code for this class:

import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;

public class ChatClient  extends UnicastRemoteObject implements ChatClientInt{
	
	private String name;
	private ChatUI ui;	
	public ChatClient (String n) throws RemoteException {
		name=n;
		}
	
	public void tell(String st) throws RemoteException{
		System.out.println(st);
		ui.writeMsg(st);
	}
	public String getName() throws RemoteException{
		return name;
	}
	
	public void setGUI(ChatUI t){ 
		ui=t ; 
	} 	
}

5 Create a new Class : ChatUI under the project ChatClientProj, copy and paste the following code for this class:

import javax.swing.*;
import javax.swing.border.*;

import java.awt.*;
import java.awt.event.*;
import java.rmi.Naming;
import java.util.*;

public class ChatUI{
  private ChatClient client;
  private ChatServerInt server;
  public void doConnect(){
	    if (connect.getText().equals("Connect")){
	    	if (name.getText().length()<2){JOptionPane.showMessageDialog(frame, "You need to type a name."); return;}
	    	if (ip.getText().length()<2){JOptionPane.showMessageDialog(frame, "You need to type an IP."); return;}	    	
	    	try{
				client=new ChatClient(name.getText());
	    		client.setGUI(this);
				server=(ChatServerInt)Naming.lookup("rmi://"+ip.getText()+"/myabc");
				server.login(client);
				updateUsers(server.getConnected());
			    connect.setText("Disconnect");			    
	    	}catch(Exception e){e.printStackTrace();JOptionPane.showMessageDialog(frame, "ERROR, we wouldn't connect....");}		  
	      }else{
	    	  	updateUsers(null);
	    	  	connect.setText("Connect");
	    	  	//Better to implement Logout ....
		}
	  }  
  
  public void sendText(){
    if (connect.getText().equals("Connect")){
    	JOptionPane.showMessageDialog(frame, "You need to connect first."); return;	
    }
      String st=tf.getText();
      st="["+name.getText()+"] "+st;
      tf.setText("");
      //Remove if you are going to implement for remote invocation
      try{
    	  	server.publish(st);
  	  	}catch(Exception e){e.printStackTrace();}
  }

  public void writeMsg(String st){  tx.setText(tx.getText()+"\n"+st);  }

  public void updateUsers(Vector v){
      DefaultListModel listModel = new DefaultListModel();
      if(v!=null) for (int i=0;i<v.size();i++){
    	  try{  String tmp=((ChatClientInt)v.get(i)).getName();
    	  		listModel.addElement(tmp);
    	  }catch(Exception e){e.printStackTrace();}
      }
      lst.setModel(listModel);
  }
  
  public static void main(String [] args){
	System.out.println("Hello World !");
	ChatUI c=new ChatUI();
  }  
  
  //User Interface code.
  public ChatUI(){
	    frame=new JFrame("Group Chat");
	    JPanel main =new JPanel();
	    JPanel top =new JPanel();
	    JPanel cn =new JPanel();
	    JPanel bottom =new JPanel();
	    ip=new JTextField();
	    tf=new JTextField();
	    name=new JTextField();
	    tx=new JTextArea();
	    connect=new JButton("Connect");
	    JButton bt=new JButton("Send");
	    lst=new JList();        
	    main.setLayout(new BorderLayout(5,5));         
	    top.setLayout(new GridLayout(1,0,5,5));   
	    cn.setLayout(new BorderLayout(5,5));
	    bottom.setLayout(new BorderLayout(5,5));
	    top.add(new JLabel("Your name: "));top.add(name);    
	    top.add(new JLabel("Server Address: "));top.add(ip);
	    top.add(connect);
	    cn.add(new JScrollPane(tx), BorderLayout.CENTER);        
	    cn.add(lst, BorderLayout.EAST);    
	    bottom.add(tf, BorderLayout.CENTER);    
	    bottom.add(bt, BorderLayout.EAST);
	    main.add(top, BorderLayout.NORTH);
	    main.add(cn, BorderLayout.CENTER);
	    main.add(bottom, BorderLayout.SOUTH);
	    main.setBorder(new EmptyBorder(10, 10, 10, 10) );
	    //Events
	    connect.addActionListener(new ActionListener(){
	      public void actionPerformed(ActionEvent e){ doConnect();   }  });
	    bt.addActionListener(new ActionListener(){
	      public void actionPerformed(ActionEvent e){ sendText();   }  });
	    tf.addActionListener(new ActionListener(){
	      public void actionPerformed(ActionEvent e){ sendText();   }  });
	    
	    frame.setContentPane(main);
	    frame.setSize(600,600);
	    frame.setVisible(true);  
	  }
	  JTextArea tx;
	  JTextField tf,ip, name;
	  JButton connect;
	  JList lst;
	  JFrame frame;
}

6 Run the ChatUI so that everything gets compiled. You can close it

7 Generate the stub for the ChatClient class using the RMIC inside the bin folder of the ChatClientProj

rmic ChatClient -> Press Enter

That’s for the Client now.

3) Packaging of the Applications

1 Copy the stub file for the server side ChatServer_stub.class to the src folder of the client as shown below:

rmi-chat-gui-12

2 Copy the stub file for the client side ChatClient_stub.class to the src folder of the server as shown below:

rmi-chat-gui-13

3 Right click on the project ChatServer, select Refresh:

rmi-chat-gui-14

4 Do the same for the ChatClientProj project, Right click and select Refresh

5 Right Click on the project ChatServer, select Export

rmi-chat-gui-15

6 Select Java –> Runnable Jar file

rmi-chat-gui-16

7 on the next screen, Select ChatServer – StartServer for the launch Configuration.
Browse for a place to save your exported jar file and click Finish, you can name it as server.jar

rmi-chat-gui-17

8 Do the same for the ChatClientProj and export it as client.jar

4) Running the Server & Client

1 The server can be run from Eclipse, or you can use the Server.jar file to run it from any PC through the command (CMD console):

java -jar Server.jar

2 Give the Client.jar file to other people connected to the network. Because the client is a GUI application, they can double click on it to run through Java Virtual Machine ( not WinRar….)
Or instead, to run it through the CMD console as :

java -jar Client.jar

Here a screenshot of the app.
rmi-chat-gui-18