package elte.java2_utikalauz5.chat; import java.rmi.Naming; import java.rmi.server.UnicastRemoteObject; import java.rmi.RemoteException; import java.rmi.RMISecurityManager; import java.util.*; /***** Java Chat Program - Szerveroldal implementációja. Használatakor ne feledjünk el a következő jogokat megadni!
grant signedBy "utikalauz" {
  permission java.net.SocketPermission "localhost", "connect,accept";
};
@link.forrásfájl {@docRoot}/../data/chat/src RMIChatServer.java @link.letöltés {@docRoot}/../data/chat RMIChatServer.jar @since Java 2 Útikalauz programozóknak 1.3 */ public class RMIChatServer extends UnicastRemoteObject implements RMIChatServerIf { /** Verziószám. */ private final static long serialVersionUID = 15L; Hashtable resztvevok; /* résztvevők beceneve és "kliensoldali" objektumuk */ public RMIChatServer() throws java.rmi.RemoteException { super(); /* Ez exportálja a távoli objektumot */ try { resztvevok=new Hashtable(); } catch (Exception e) { System.out.println("ChatServer objektum nem hozható létre."); } } /*** * Az összes résztvevőnek eljuttat egy (nem üres) üzenetet ***/ private Hashtable resztvevokErtesitese(String nev, String uzenet) { Hashtable kiesettek; kiesettek=new Hashtable(); synchronized (resztvevok) { Enumeration rvEnum=resztvevok.keys(); while (rvEnum.hasMoreElements()) { /* Az összes résztvevőnek ... */ String rnev=(String) rvEnum.nextElement(); RMIChatClientIf r=(RMIChatClientIf) resztvevok.get(rnev); try { if (!uzenet.equals("")) /* Ha a szöveg nem üres ... */ { r.uzenetFogadas(nev,uzenet); /* akkor elküldjük a kliensnek */ } } catch (java.rmi.RemoteException re) { /* rnev résztvevő nem elérhető - felveszem mint kiesettet */ kiesettek.put(rnev,resztvevok.get(rnev)); resztvevok.remove(rnev); } } } return kiesettek; /* Visszaadom a kiesettek névsorát */ } /*** * Az összes résztvevőnek eljuttat egy "XY belépett/kilépett" üzenetet * Itt az üzenet kiírása mellett a kliensoldali társak listájának * aktualizálása fontos, ebben különbözik a normál kiíró metódustól. ***/ private Hashtable kibelepesErtesites(String nev, boolean ki_e) { Hashtable kiesettek; kiesettek=new Hashtable(); synchronized (resztvevok) { Enumeration rvEnum=resztvevok.keys(); while (rvEnum.hasMoreElements()) { String rnev=(String) rvEnum.nextElement(); RMIChatClientIf r=(RMIChatClientIf) resztvevok.get(rnev); try { if (ki_e) { r.uzenetFogadas("",nev+" kilépett."); r.tarsKilepes(nev); } else { r.uzenetFogadas("",nev+" belépett a szobába."); r.tarsBelepes(nev); } } catch (java.rmi.RemoteException re) { /* rnev résztvevő nem elérhető - felveszem mint kiesettet */ kiesettek.put(rnev,resztvevok.get(rnev)); resztvevok.remove(rnev); } } } return kiesettek; } /*** * Az összes résztvevőnek eljuttat egy "XY kilépett" üzenetet * Itt az üzenet kiírása mellett a kliensoldali társak listájának * aktualizálása fontos, ebben különbözik a normál kiíró metódustól. ***/ private Hashtable kilepesErtesites(String nev) { return kibelepesErtesites(nev,true); } /*** * Az összes résztvevőnek eljuttat egy "XY belépett" üzenetet * Itt az üzenet kiírása mellett a kliensoldali társak listájának * aktualizálása fontos, ebben különbözik a normál kiíró metódustól. ***/ private Hashtable belepesErtesites(String nev) { return kibelepesErtesites(nev,false); } /*** * Kitörli a résztvevők névsorából a paraméterben megadott * (elérhetetlennek vélt) klienseket. * A kiesettnek véltek már ki vannak véve a résztvevők közül, * így az értesítés csak az aktív klienseknek lesz elküldve. * Ha közben - az értesítések során - valaki kiesne ... akkor újból * teszünk egy kört ... (végesség oka: rekurzív meghívás során a * résztvevők száma csökken - végtelen ciklus e rekurzióból nem lehet). ***/ public void RIP(Hashtable kiesettek) { synchronized (kiesettek) { Enumeration rvEnum=kiesettek.keys(); while (rvEnum.hasMoreElements()) { /* Az összes kiesettről */ String rnev=(String) rvEnum.nextElement(); Hashtable kiesettek2= /* Üzenet az élőknek */ resztvevokErtesitese("",rnev+" kapcsolata bontott!"); RIP(kiesettek2); /* Újabb kiesettek ... béke poraikra ... */ } } } /*** * A második paraméterben megadott nevű csetelő kirúgta az első * paraméterben megadott nevű társát. * Ha létezik a kirúgott nevű csetes, kitesszük a csetből és * értesítjük a többieket. * Megj.: jelenleg mindenki rúgdoshat - ide lehetne beírni például * olyan ellenőrzést, hogy csak bizonyos nevű csetesek rúghatnak ki * másokat. Mivel ez nem bonyolult algoritmus (milyen nevet adtunk * az "if" utasításnak :-) ), és nem csetspecifikus, ezért itt most * ilyent nem csinálunk. ***/ private void kirug(String nev, String ki_rugta_ki) { boolean letezonev=false; synchronized (resztvevok) { if (letezonev=resztvevok.containsKey(nev)) { RMIChatClientIf r=(RMIChatClientIf) resztvevok.remove(nev); /* A kirúgottat kiszedtük a résztvevők közül, és értesítjük ... */ try { r.uzenetFogadas("","Kirúgtak a csetből,biztos jó okuk volt rá."); r.tarsKilepes(nev); r.kirugtak(); } catch (java.rmi.RemoteException re) { // kirúgott résztvevő nem elérhető - nem érdekel, úgyis kitettük :-) } } } if (letezonev) { /* Ha kirúgtunk valakit, értesítjük a többieket */ Hashtable kiesettek = resztvevokErtesitese("", nev+" kilepett a szobabol, mert "+ki_rugta_ki+" kirugta."); RIP(kiesettek); } } public int uzenetFogadas(String nev, String szoveg) throws java.rmi.RemoteException { char elsojelhavan=' '; if (szoveg.length() > 0) { elsojelhavan=szoveg.charAt(0); } /* Ha az első jel nem egy /,akkor visszaírjuk az üzenetet a csetelőknek */ if (elsojelhavan != '/') { Hashtable kiesettek = resztvevokErtesitese(nev,szoveg); RIP(kiesettek); } else { /* Egy parancsról van szó */ if (szoveg.startsWith("/kirug ")) /* kirúgás? */ { kirug(szoveg.substring(7),nev); /* ha igen, kitesszük az áldozatot */ } else System.err.println("Ismeretlen parancs ..."); } return resztvevok.size(); /* Visszaadjuk a résztvevők számát */ } public Hashtable nevlistaSzinkronizalas() throws java.rmi.RemoteException { Hashtable csaknevek=new Hashtable(); /* Összeállítunk egy hashtáblát, benne kulcsként a résztvevők neveivel */ synchronized (resztvevok) { Enumeration rvEnum=resztvevok.keys(); while (rvEnum.hasMoreElements()) { String rnev=(String) rvEnum.nextElement(); csaknevek.put(rnev,"mindegymi"); } } return csaknevek; /* Visszaadjuk a hashtáblát a kliensnek */ } public void tarsBelepes(String nev, RMIChatClientIf Kli) throws java.rmi.RemoteException { // System.out.println("Belepett: "+nev); // Ez most nem kell ... // feltöltjük az uj bejelentkezö nev-listajat synchronized (resztvevok) { /* Felvesszük a belépőt a résztvevők közé */ resztvevok.put(nev,Kli); /* IP cím alapjáni tiltás esetén itt lehet-*/ } /* ne visszautasítani a krónikus rosszakat */ Hashtable kiesettek=new Hashtable(); /* Ha közben kiesne valaki ... */ /* új belépő névlistája */ synchronized (resztvevok) { Enumeration rvEnum=resztvevok.keys(); while (rvEnum.hasMoreElements()) { String rnev=(String) rvEnum.nextElement(); try { if (!rnev.equals(nev)) { Kli.tarsBelepes(rnev); /* Névlista aktualizálása résztvevőknél */ } } catch (java.rmi.RemoteException re) { /* rnev résztvevő nem elérhető? Pedig most akart volna belépni */ kiesettek.put(rnev,resztvevok.get(rnev)); resztvevok.remove(rnev); System.err.println("tarsBelepes: kliens visszahívás sikertelen"); } } } RIP(kiesettek); kiesettek=belepesErtesites(nev); RIP(kiesettek); } public void tarsKilepes(String nev) throws java.rmi.RemoteException { // System.out.println("Kilepett: "+nev); // Ez most nem kell ... synchronized (resztvevok) { RMIChatClientIf Kli = (RMIChatClientIf) resztvevok.remove(nev); } /* Többiek értesítése */ Hashtable kiesettek = kilepesErtesites(nev); RIP(kiesettek); } /*** * A szerver főprogramja * Létrehozzuk a szerverobjektumot, bejegyezzük a registrybe. * A többi már csak a kliensek ... azaz a csetelők feladata ... ***/ public static void main(String args[]) { System.setSecurityManager(new RMISecurityManager()); String hn="localhost"; if (args.length > 0) hn=args[0]; try { RMIChatServer n = new RMIChatServer(); Naming.rebind("rmi://"+hn+"/DefaultChatSzoba",n); System.out.println("ChatServer fut ..."); } catch (Exception e) { System.out.println("ChatSzerver nem indítható ..."); System.out.println("Hiba oka:"+e); } } }