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);
}
}
}