//import java.util.Date; import java.io.*; import java.rmi.Naming; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; import java.util.*; public class ClientRMIVC extends UnicastRemoteObject implements ClientInterfaceVC, Runnable { private volatile Thread clientThread = null; static final long serialVersionUID = 42L; private String local_name; private Random rand = new Random(); private Tableau local_tableau = new Tableau(); private Vector clients = new Vector(); private HashMap vc = new HashMap(); // vecteur horloge private MyQueue q = new MyQueue(); // queue des message en attente de livraison (affichage) private ClientRMIVC(String name) throws RemoteException { super(); local_name = name; vc.put(local_name, new Integer(0)); } public synchronized void register(ClientInterfaceVC client) throws RemoteException { if (!(clients.contains(client))) { clients.addElement(client); vc.put(client.getName(), new Integer(0)); System.out.println("Nouveau client " + client.getName()); } } public synchronized void unregister(ClientInterfaceVC client) throws RemoteException { if (clients.removeElement(client)) { vc.remove(client.getName()); System.out.println("Client a quitte"); } else { System.out.println("Client n'etais pas enregistre"); } } public String getName() throws RemoteException { return local_name; } public static String getInputLine() { InputStreamReader isr; BufferedReader stdin; isr = new InputStreamReader(System.in); stdin = new BufferedReader(isr); String input = new String(); try { input = stdin.readLine(); } catch (IOException e) { e.printStackTrace(); } return input; } private void printHeader() { System.out.println("Tableau"); System.out.println("------------------------------------------------"); } private void broadcastMsg(String strmsg) throws RemoteException, InterruptedException { // on increment de 1 vc.put(local_name, new Integer(((Integer)vc.get(local_name)).intValue() + 1)); Msg msg = new Msg(strmsg, local_name, new HashMap(vc)); // on l'affiche locallement deliverMsg(msg); // on transmet aux autres for (Enumeration e = clients.elements() ; e.hasMoreElements() ;) { ClientInterfaceVC client = (ClientInterfaceVC) e.nextElement(); try { Thread.sleep((long)Math.abs(rand.nextInt(2000))); // on envoi le message client.addMsg(msg); } catch (RemoteException ex) { System.out.println("Client a quitte"); unregister(client); } } } public void addMsg(Msg msg) throws RemoteException { System.out.println("Got message"); q.addQ(msg); } public void deliveryThread() throws InterruptedException { while(true) { for(int i=0; i < q.size(); i++) { Msg msg; HashMap vcm; String source; boolean good = true; msg = q.peek(); vcm = msg.getVC(); source = msg.getSource(); Iterator iter = vcm.keySet().iterator(); while (iter.hasNext()) { String cur = (String)iter.next(); if (cur != source) if (((Integer)vcm.get(cur)).intValue() > ((Integer)vc.get(cur)).intValue()) good = false; } if (good == true && ((Integer)vcm.get(source)).intValue() == ((Integer)vc.get(source)).intValue() + 1) { // c'est bon on affiche le message deliverMsg(q.removeQ()); vc.put(source, new Integer(((Integer)vc.get(source)).intValue() + 1)); break; } else { // on remet le message a la queue de la queue msg = q.removeQ(); q.addQ(msg); System.out.println("mise en attente du message " + msg.getMsg() + " par " + msg.getSource()); } } Thread.sleep(50); } } public void deliverMsg(Msg msg) { String strmsg = new String(msg.getSource() + " : " + msg.getMsg()); local_tableau.addMsg(strmsg); printHeader(); local_tableau.print(); } public void start() { if (clientThread == null) { clientThread = new Thread(this, "Client"); clientThread.start(); } } public void run() { // on demarre le reordonnanceur de queue new Thread(){ public void run() { try { ClientRMIVC.this.deliveryThread(); } catch (InterruptedException ex) { System.out.println("Problem with release thread"); } } }.start(); while (true) { //Date now; // on attend de recevoir un message a l'entree final String msg = getInputLine(); // on affiche le nouveau message sur le tableau System.out.println("Creating broadcast thread"); new Thread(){ public void run() { try { ClientRMIVC.this.broadcastMsg(msg); } catch (InterruptedException ex) { System.out.println("Problem broadcasting"); } catch (RemoteException ex) { System.out.println("Problem broadcasting"); } } }.start(); } } public static void main(String[] args) { // args : ./ClientRMIVC localnickanme remote1 remote2 ... remoten // 0 1 2 n int i; try { ClientRMIVC client = new ClientRMIVC(args[0]); // on se met a l'ecoute Naming.rebind(args[0], client); // on se connect aux autres usagers for (i = 1; i < args.length; i++) { ClientInterfaceVC nclient = (ClientInterfaceVC) Naming.lookup(args[i]); nclient.register((ClientInterfaceVC)client); client.register((ClientInterfaceVC)nclient); } client.start(); } catch (Exception e) { System.err.println("ClientRMIVC exception: " + e.toString()); e.printStackTrace(); } } } class Msg implements Serializable { private static final long serialVersionUID = 7526471155622776147L; private HashMap vc = new HashMap(); // vecteur d'horloge private String source = new String(); // emetteur du message private String msg = new String(); // le message public Msg(String nmsg, String nsource, HashMap nvc) { msg = nmsg; source = nsource; vc = nvc; } public String getMsg() { return msg; } public String getSource() { return source; } public HashMap getVC() { return vc; } } class MyQueue extends Vector { static final long serialVersionUID = 42L; public void addQ(Msg msg) { addElement(msg); } public Msg removeQ() { Msg msg = peek(); removeElementAt(0); return msg; } public Msg peek() { if (size() == 0) throw new EmptyStackException(); return (Msg) elementAt(0); } public boolean emptyQ() { return size() == 0; } } class Tableau { private Vector messages; public Tableau() { messages = new Vector(); } public void addMsg(String msg) { messages.add(msg); } public void print() { int i; for (i = 0; i < messages.size(); i++) { System.out.println(messages.get(i)); } System.out.println("\n"); } }