I have created interfaces and implementations for Chat Server, Client, and Message. I compiled all the Java files. Then I compiled implementation classes using rmic to create stubs. I started the rmi registry. I started the server implementation and it works as expected; confirming that he registered with RMI and he returns a list of active clients. I am now stuck as when I try to run a client implementation if it is below the command
start java ChatClientImpl
the command field appears within a second and disappears. I do not know how to make the client work.
Does anyone have any suggestions on how to get the client to work and work?
Here is the complete code for the application.
Chat client interface
package p;
public interface ChatClient extends java.rmi.Remote {
public void processMessage(MessageImpl inMessage) throws
java.rmi.RemoteException;
public void ping() throws java.rmi.RemoteException;
public String getName() throws java.rmi.RemoteException;
}
Chat client implementation
package p;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
public class ChatClientImpl extends UnicastRemoteObject implements ChatClient{
private static final long serialVersionUID = 3056117484716596895L;
private ChatServer listServer = null;
private ArrayList<ChatClient> knownClients = null;
private String clientName = null;
private ArrayList<GUID> processedMessages = null;
private JChatClient gui = null;
public ChatClientImpl(String inServerName,
String inClientName) throws Exception{
this.clientName = inClientName;
this.listServer = (ChatServer) Naming.lookup(inServerName);
this.processedMessages = new ArrayList<GUID>();
this.listServer.register(this);
ChatClient[] newClients = this.listServer.getClients();
this.knownClients = new ArrayList<ChatClient>();
this.addClients(newClients);
}
protected void setGUI(JChatClient inGUI){
this.gui = inGUI;
}
private void addClients(ChatClient[] inClients){
for(int i = 0; i < inClients.length; i++){
if(!this.knownClients.contains(inClients[i])){
this.knownClients.add(inClients[i]);
}
else{
System.err.println("already know that peer - will not add.");
}
}
}
public void handleMessage(String inString){
MessageImpl msg = new MessageImpl(this,inString);
Iterator<ChatClient> i = this.knownClients.iterator();
while(i.hasNext()){
ChatClient knownClient = i.next();
try {
knownClient.processMessage(msg);
} catch (RemoteException e) {
i.remove();
}
}
}
public void processMessage(MessageImpl inMessage) throws java.rmi.RemoteException{
System.out.println("message received");
if(this.processedMessages.contains(inMessage.id)) return;
else{
System.err.println(inMessage.id);
this.processedMessages.add(inMessage.id);
System.err.println("have now processed " + this.processedMessages.size());
}
this.gui.updateDisplay(inMessage);;
HashSet<ChatClient> recipients = inMessage.getRecipients();
for (ChatClient chatClient : recipients) {
if(knownClients.contains(chatClient)){
System.out.println("already know about that client");
}
else{
System.out.println("discovered a new recipient");
this.knownClients.add(chatClient);
}
}
Iterator<ChatClient> iter = this.knownClients.iterator();
while(iter.hasNext()){
ChatClient chatClient = iter.next();
if(recipients.contains(chatClient)){
System.err.println("aready sent to that client");
}
else{
System.out.println("sending to a new client");
try {
chatClient.processMessage(inMessage);
} catch (RemoteException e) {
iter.remove();
}
}
}
}
public void ping() throws java.rmi.RemoteException{
}
public String getName() throws java.rmi.RemoteException{
return this.clientName;
}
}
Chat server interface
package p;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface ChatServer extends Remote {
public abstract void register(ChatClient inClient) throws RemoteException;
public abstract ChatClient[] getClients() throws RemoteException;
}
Chat Server Implementation
package p;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
private List<ChatClient> clients = null;
public ChatServerImpl() throws RemoteException{
this.clients = new ArrayList<ChatClient>();
}
@Override
public void register(ChatClient inClient) throws RemoteException{
if(!this.clients.contains(inClient)) this.clients.add(inClient);
}
@Override
public synchronized ChatClient[] getClients() throws RemoteException{
if(this.clients.size() > RETURN_SET_SIZE){
List<ChatClient> clientSample = randomSample2(this.clients, RETURN_SET_SIZE);
return (ChatClient[]) this.clients.toArray( new ChatClient[ this.clients.size() ] );
}
else return (ChatClient[]) this.clients.toArray( new ChatClient[ this.clients.size() ] );
}
private static <T> List<T> randomSample2(List<T> items, int m){
Random rnd = new Random();
for(int i=0;i<items.size();i++){
int pos = i + rnd.nextInt(items.size() - i);
T tmp = items.get(pos);
items.set(pos, items.get(i));
items.set(i, tmp);
}
return items.subList(0, m);
}
public void run(){
while(true){
try {Thread.sleep(PING_SLEEP_DURATION);} catch (Exception e) {}
System.out.println("Performing Update");
ArrayList<ChatClient> copy = new ArrayList<ChatClient>(this.clients);
System.out.println("Checking " + copy.size() + " clients");
for (ChatClient chatClient : copy) {
try {
chatClient.ping();
} catch (RemoteException e) {
System.out.println("Removing a client.");
this.clients.remove(chatClient);
}
}
}
}
public static void main(String[] args) throws Exception{
ChatServer server = new ChatServerImpl();
Naming.rebind("rmi://localhost/chat", server);
System.out.println("Registration with RMI complete.");
Thread th = new Thread(((ChatServerImpl)server));
th.start();
System.out.println("Server thread now running.");
}
}
Message interface
package p;
import java.util.HashSet;
public interface Message {
public abstract void addRecipient(ChatClient inClient);
public abstract HashSet<ChatClient> getRecipients();
public abstract String getContent();
public abstract String getSource();
}
package p;
import java.util.HashSet;
public class MessageImpl implements java.io.Serializable, Message {
private static final long serialVersionUID = 8914588083609635659L;
public final GUID id;
public final HashSet<ChatClient> passedThrough = new HashSet<ChatClient>();
private String content = null;
private ChatClient client = null;
public MessageImpl(ChatClient s, String inContent) {
this.id = new GUID(s);
this.client = s;
this.passedThrough.add(s);
this.content = inContent;
}
@Override
public void addRecipient(ChatClient inClient){
this.passedThrough.add(inClient);
}
@Override
public HashSet<ChatClient> getRecipients(){
return this.passedThrough;
}
@Override
public String getContent(){
return this.content;
}
public String getSource(){
try {
return this.client.getName();
} catch (Exception e) {
return "client uncreachable";
}
}
}
class GUID implements java.io.Serializable {
static final long serialVersionUID = 4928185858035458591L;
public final ChatClient source;
private static int nextID;
private int id = 0;
public GUID(ChatClient s) {
this.source = s;
synchronized(GUID.class) {
this.id = nextID++;
}
}
public final int hashCode() {
return source.hashCode() + id;
}
public final boolean equals(Object that) {
if (!(that instanceof GUID)) return false;
GUID m2 = (GUID)that;
return id == m2.id && source.equals(m2.source);
}
}
GUI
package p;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.io.IOException;
import java.rmi.RemoteException;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTextPane;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;
public class JChatClient extends JFrame implements java.awt.event.ActionListener{
private ChatClientImpl model = null;
protected JTextField inputField = null;
private JTextPane historyPane = null;
public JChatClient(ChatClient inClient, String inUserName) throws RemoteException {
super("Chat: " + inUserName);
this.model = (ChatClientImpl) inClient;
this.model.setGUI(this);
super.setLayout(new BorderLayout());
this.historyPane = new JTextPane();
this.historyPane.setAutoscrolls(true);
this.historyPane.setEditable(false);
this.historyPane.setPreferredSize(new Dimension(100,100));
JScrollPane historyView = new JScrollPane(historyPane);
historyView.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
historyView.setAutoscrolls(true);
super.add(historyView, BorderLayout.CENTER);
this.inputField = new JTextField("", 20);
this.inputField.addActionListener(this);
JPanel bottom = new JPanel();
bottom.setLayout(new BoxLayout(bottom,BoxLayout.X_AXIS));
bottom.add(inputField);
super.add(bottom, BorderLayout.SOUTH);
this.centerAndSetVisible();
}
public void updateDisplay(MessageImpl inMessage) {
this.printText("\n" + inMessage.getSource() + ": " + inMessage.getContent(),Color.BLACK);
}
public void actionPerformed(ActionEvent e) {
String msg = inputField.getText();
if (msg.length() > 0) {
inputField.setText("");
this.model.handleMessage(msg);
}
}
private void printText(String inText, Color inColor){
StyledDocument doc = historyPane.getStyledDocument();
SimpleAttributeSet attr = new SimpleAttributeSet();
StyleConstants.setForeground(attr, inColor);
try {
doc.insertString(doc.getLength(),inText,attr);
historyPane.setCaretPosition(doc.getLength());
} catch (Exception ex) {
ex.printStackTrace();
}
}
private void centerAndSetVisible(){
this.pack();
this.setPreferredSize(new Dimension(300, 300));
Dimension labelSize = this.getPreferredSize();
Dimension sd = Toolkit.getDefaultToolkit().getScreenSize();
int x = ( sd.width - labelSize.width )/2;
int y = ( sd.height - labelSize.height )/2;
this.setLocation(x, y);
setSize(new Dimension(labelSize.width, labelSize.height));
this.setVisible(true);
this.setAlwaysOnTop(false);
}
public static void main(String[] args) throws Exception{
ChatClientImpl client = new ChatClientImpl(args[0], args[1]);
new JChatClient(client,args[1]);
}
}