Diagramma delle classi

Transcript

Diagramma delle classi
Realizzato da:
Enrico Maria Caruso
Fabio Affè
Indice
Introduzione:
Cos’è Gossip?
Obiettivi del testo
Contenuto delle varie sezioni
Dettagli Implementativi:
Strumenti e tecniche adottate
Struttura del progetto
- Diagramma delle classi:
- Dettagli realizzativi delle classi principali
- Breve descrizione delle classi di appoggio
- Diagramma delle attività
- Diagramma dei casi d’uso
- Narrazione dei casi d’uso
- Diagrammi di sequenza relativi ad ogni caso d’uso.
Architettura del Sistema
Dislocazione dei componenti
Guida per l’utente amministratore
Funzionalità e servizi del BootStapServer e dei MessageServer
Attivazione del registry RMI
Attivazione del MessageServer e del BootStrapServer
Guida per l’utente generico
Passi principali
Avvio del Client
Presentazione interfaccia
Sviluppi futuri
Bibliografia
Introduzione:
Cos’è Gossip?
Gossip è un software che fornisce un servizio di scambio messaggi in tempo reale fra utenti connessi in rete
ed un servizio email-like per gli utenti offline.
Obiettivi del testo
Lo scopo di questo testo è di illustrare brevemente le varie fasi che hanno portato alla realizzazione del
progetto descrivendo i file sorgente e le strutture dati utilizzate. Fornisce inoltre le informazioni necessarie
all'utilizzo di Gossip sia per gli amministratori della rete che per gli utenti generici.
Contenuto delle varie sezioni
Il presente testo si divide in quattro sessioni principali:
Dettagli implementativi: che descrive le tecniche e gli strumenti usati, fornisce un’ analisi
dettagliata della struttura del progetto mediante diagrammi UML, spiega il funzionamento delle
classi principali, e illustra l’esecuzione dei thread mediante diagrammi di sequenza
Architettura: che illustra attraverso le viste ibride (UML) la dislocazione dei componenti software
e hardware di Gossip.
Guida per l’amministratore: che mostra informazioni riguardante il modo di compilazione e di
esecuzione del codice relativo ai servers (BootStrapServer e MessageServer).
Guida per l’utente generico: che mostra come va compilato ed eseguito il client Gossip e ne
descrive le principali funzionalità.
Dettagli Implementativi
Strumenti e tecniche adottate
Il progetto “Gossip” è stato realizzato utilizzando principalmente gli strumenti forniti dal centro di calcolo
quali le macchine dei laboratori e la rete del polo Fibonacci. Per la stesura del codice è stato usato
l’ambiente di sviluppo eclipse su workstation linux utilizzando le principali tecniche di programmazione
di rete. Tra le tecniche adottate citiamo RMI, i protocolli TCP e UDP ed il Multicast.
Struttura del progetto
La realizzazione di programmi che lavorano in rete come tutta la programmazione ad oggetti in genere
comporta scelte progettuali impegnative che riguardano vari ambiti. La ricerca e la creazione
di nuovi oggetti che semplificano la gestione ed il trattamento dei dati, così come la scelta dei
metodi di comunicazione è spesso ardua e di gran lunga più dispendiosa in termini di tempo
rispetto alla programmazione vera e propria. Nella realizzazione di Gossip abbiamo cercato di
sfruttare al massimo le conoscenze acquisite durante il corso combinandole con quelle dei
corsi precedenti. Abbiamo semplificato al massimo la fase di scrittura del codice scegliendo
le strutture dati più adeguate alle nostre esigenze e modellando su carta le varie funzionalità
da implementare prima della vera e propria programmazione.
• Diagramma delle classi
Fig.1 GOSSIP: Diagramma delle Classi
Di seguito verranno descritte le classi che compongono Gossip con particolare enfasi sulle principali scelte
di progetto effettuate.
Dettagli realizzativi delle classi principali
BootStrapServer
Crea un nuovo oggetto server di tipo BootStrapServerImpl su cui effettua il Naming.rebind per aggiungerlo
al registro RMI.
BootStrapServerImpl
La classe presenta metodi RMI messi a disposizione ai client GOSSIP. Il costruttore crea un vettore
ClientList, ed un file (struttura.txt) dove vengono salvate tutte le info su ogni utente che si registra. La
classe consta dei seguenti metodi sincronizzati:
doRegistrazione
Metodo in RMI che permette di fare la registrazione di un utente. Il metodo controlla se l'utente e' gia'
registrato accedendo al file struttura.txt, se non lo e' viene registrato altrimenti manda al client un
messaggio con la frase: “Ti sei gia' registrato con questo nome”
doLogin
Permette di fare il login ad un utente. Il metodo controlla se l'utente e' registrato accedendo al file
struttura.txt, se e' loggato, e procede di conseguenza aggiornando il file contatti.txt e informando gli altri
Client interessati dell'avvenuto cambiamento di stato (CallBack RMI). A login effettuato viene assegnato al
Client un MessageServer per i messaggi offline e vengono inviate a tale MessageServer le informazioni sul
client sotto forma di Messaggio (vedi descrizione della classe)
doLogout
Permette di fare il logout ad un utente
Il metodo modifica lo stato dell’utente nel file struttura.txt e nel file contatti.txt, successivamente informa
gli altri Client interessati dell'avvenuto cambiamento di stato mediante l’uso di CallBack RMI.
doVerificaContattoIn
Permette di aggiungere un utente nella lista dei contatti di ingresso controllando se il contatto che voglio
aggiungere e' registrato e aggiorna il file contatti.txt
doVerificaContattoOut
Permette di aggiungere un utente nella lista contatti di uscita. Controlla se l'utente che voglio aggiungere e'
registrato e se l’utente mi ha già inserito tra i suoi contatti in entrata e aggiorna il file contatti.txt
doCallbacks
Questo metodo e' usato per informare tutti gli utenti registrati dei cambiamenti di stato dei loro contatti.
Client
La classe Client contiene il metodo main che lancia l’interfaccia grafica di Gossip e gestisce gli eventi
generati dai pulsanti dell’interfaccia utente Gossip.
Mantiene “chats” un array di ChatElement (vedi descrizione della classe, pag. 7) contenente le chat
attualmente in esecuzione. Implementa anche il metodo vectorToJTextArea che viene usato per convertire
la lista dei contatti fornita dal server al login nell’elenco dei contatti della JTextArea dell’interfaccia
grafica. Questo metodo permette di scrivere gli elementi da un vettore di Utenti ad un oggetto JTextArea
per la visualizzazione dei contatti. I contatti online verranno indicati con un simbolo “+”.
ClientImpl
La classe presenta i seguenti metodi:
setStato
permette di settare lo stato dell'utente al valore passato come parametro
name
ritorna il nome dell’utente
ip
ritorna l’indirizzo ip dell’host su cui si trova dell’utente
stato
ritorna lo stato in cui si trova l’utente
callback
notifica all’utente il cambio di stato dei sui contatti
notifyMe
viene utilizzato dal Server quando vuole notificare un messaggio all’utente. I messaggi di notifica vengono
poi visualizzati su un’etichetta nell’interfaccia grafica del Client.
Chat
Serve per la comunicazione realtime tra due Utenti, la connessione è stata implementata con il protocollo
Tcp. Il thread Chat lancia un’interfaccia grafica che permette all’utente di inviare messaggi e di
visualizzare quelli ricevuti. Per la ricezione di messaggi crea e lancia il thread Lettura (descritto di seguito).
Lettura
Thread, lanciato da chat, che resta in attesa di leggere i messaggi di testo inviati su una socket. Chi invia è
l’utente con cui ho instaurato una connessione Tcp. Implementa il metodo esci() che termina il thread.
MessaggiOffline
Questa classe permette la comunicazione tra l’utente e il messageserver. Lancia un’interfaccia grafica che
permette all’utente di scrivere i propri messaggi ad un utente che al momento non è in linea.
MessaggiOffline comunica direttamente con il MessageServer inviando pacchetti Udp sulla porta su cui il
thread SalvaMessaggi (lanciato dal MessageServer al suo avvio) è in attesa. L’interfaccia è formata da una
JTextArea e da due pulsanti (“Esci” e “Invia”). “Invia” non fa altro che prendere il testo dalla TextArea
incapsularlo in un oggetto Messaggio (vedi descrizione della classe, pag. 8) e spedirlo al messageserver.
“Esci” chiude semplicemente la finestra.
LeggiMessaggiOffline ha lo scopo di far apparire sullo schermo dell’utente una finestra contenente tutti i
messaggi che gli sono stati inviati quando non era in linea
MessageServer
Crea e lancia il thread SalvaMessaggi e il thread RecuperoMessaggi.
Crea un collegamento multicast ed entra a farne parte dopo di che si mette in attesa di messaggi.
I messaggi attesi sono:
“Dammi”
Inviato dal BootStrapServer, il MessageServer risponderà il numero di righe presenti nel “nomefile.txt”
creato al suo avvio (nomefile è il nome del file passato da riga di comando, vedi pag. 22). Il
BootStrapServer potrà così scegliere il MessageServer da assegnare al Client minimizzandone il carico.
“Ric” seguito dal nome del contatto
Inviato da RecuperoMessaggio in multicast a tutti i MessageServer per chiedere tutti i messaggi che sono
destinati al contatto. Tali messaggi verranno inviati a RecuperoMessaggio già formattati per la stampa a
video.
Se riceve un messaggio diverso dai precedenti vuol dire che il BootStrapServer stà effettuando il login di
un utente ed ha perciò inviato una stringa contenente le informazioni sul client sottoforma di Messaggio. Il
MessageServer, dopo aver inviato una richiesta (“Ric”+nome contatto) in multicast a tutti gli altri
MessageServer, sarà quindi in grado di rispondere direttamente al client con i messaggi ricevuti.
RecuperoMessaggio
E’ un thread lanciato dal MessageServer con il nome e l’ip dell’utente destinatario dei messaggi che il
MessageServer intende recuperare come parametri. Invia a tutti i message server, compreso se stesso, in
multicast, una richiesta di messaggi appartenti all'utente ed attende le risposte che formatta in una stringa
ed invia al client in UDP.
SalvaMessaggi
E’ un thread lanciato dal MessageServer. Ha il compito di scrivere su file i messaggi inviati dai client che
sono stati assegnati al MessageServer verso altri utenti non loggati in quel momento.
Resta in attesa di riceve datagrammi, contenenti il messaggio da formattare e salvare, sulla porta 15000,
dopo aver salvato il messaggio si rimette in attesa.
ThreadAccept
Ha lo scopo di accettare le connessioni TCP provenienti dagli altri utenti che vogliono avviare una chat con
il Client. Va in attesa di connessioni sulla porta 40000, ogni volta che accetta una connessione aggiunge
all’array di ChatElement “chats”, del Client, un nuovo oggetto contenente un thread Chat ed avvia tale
thread per gestire la comunicazione. Dopodichè si rimette in attesa di nuove connessioni.
Breve descrizione delle classi di appoggio
ChatElement
Permette di contenere oggetti di tipo Chat assieme agli InetAddress dei client interessati ed al nome del
destinatario della comunicazione. Gli oggetti di questo tipo verranno gestiti dal Client nell’array chats.
Questo permette ad un utente di avviare contemporaneamente più Chat verso gli amici con cui vuole
scambiare informazioni e di identificare tali chat univocamente all’interno dell’array. L’identificazione
univoca di una chat è indispensabile per la chiusura della chat stessa, infatti se uno dei due utenti interessati
nella comunicazione chiude la propria schermata di chat essa verrà chiusa anche nell’altro host.
Questa classe presenta il metodo whereIsInChats che permette di conoscere in che posizione di chats è
presente una Chat verso l'utente destinatario passato come parametro. E’ così possibile impedire ad un
utente di aprire più chat con lo stesso destinatario.
ListaContatti
E’ un oggetto dove vengono memorizzate le informazioni riguardanti i contatti di ingresso, di uscita e il
message server assegnato ad un utente (proprietario). Questa struttura funge da appoggio a diverse classi e
contiene:
contattiin: un vettore che conterrà i contatti di ingresso
contattiout: un vettore che conterrà i contatti di uscita
proprietario: una stringa che rappresenta in proprietario di tali variabili
msgServAss: una stringa che rappresenta il message server assegnato al proprietario
Nel costruttore vengono inizializzate tali variabili.
Abbiamo deciso di implementare tale oggetto per facilitare l’invio delle informazioni necessarie al Client
da parte del BootStrapServer (Es: nel login).
La classe ListaContatti presenta i metodi di seguito descritti:
stringToListaContatti
converte un oggetto di tipo stringa in un oggetto di tipo ListaContatti, la stringa passata come parametro
deve essere adeguatamente formattata.
Es: proprietario*contattoin1*..*contattoinN*$*contattoout1*..*contattooutN*
ListaContattiToString
converte un oggetto di tipo ListaContatti in un oggetto di tipo Stringa, la stringa risultante è formattata nel
seguente modo: proprietario*contattoin1*..*contattoinN*$*contattoout1*..*contattooutN*
containsIn
controlla se nel vettore contattiin è già presente un contatto uguale a quello che voglio inserire
containsOut
controlla se nel vettore contattiout è già presente un contatto uguale a quello che voglio inserire
containsIpInOut
controlla se nel vettore contattiout è già presente un contatto con indirizzo ip uguale a quello che voglio
inserire
whereIsInOut
trova la posizione nel vettore contattiout che contiene l’utente con nome uguale a quello passato come
parametro al metodo
Messaggio
Questa classe rappresenta una struttura che incapsula oltre al messaggio che un mittente spedisce ad un
destinatario, anche le informazioni del mittente e del destinatario. Per informazioni si intende il nome del
mittente e del destinatario del messaggio ed i loro indirizzi ip. Principalmente viene usata per i messaggi
offline (classe descritta a pag. 6)ed anche per altre operazioni.
Questa struttura contiene:
nomeMittente: che rappresenta il nome del mittente del messaggio, in forma testuale
nomeDestinatario: che rappresenta il nome del destinatario del messaggio, in forma testuale
msg: rappresenta il messaggio da spedire
ipMitt: rappresenta l'indirizzo ip del mittente
Dest: rappresenta l'indirizzo ip del destinatario
e presenta i seguenti metodi:
msgToByte
permette di trasferire un oggetto di tipo Messaggio in un array di byte, l’operazione viene eseguita
chiamando il metodo getBytes() su una stringa formattata nel seguente modo:
nomeMittente*nomeDestinatario*msg*ipMitt*ipDest
stringToMsg
permette di trasformare una stringa in un oggetto di tipo Messaggio, la stringa passata deve essere
formattata come sopra
byteToMsg
è l’operazione inversa di msgToByte, come parametro riceve un array di byte e lo converte in un oggetto di
tipo Messaggio mettendo nei vari campi i rispettivi valori
Utente
È una struttura contenente le informazioni di ogni utente quali: il nome (name), l’indirizzo ip (ip) dell’host
su cui si trova in quel momento e lo stato (loggato) in cui si trova in quel momento (loggato o non loggato),
la classe presenta i metodi illustrati di seguito:
stringToUtente
questo metodo permette di trasformare una stringa in un oggetto utente, la stringa è formattata nel modo
seguente:
“name ip loggato”
sameName
permette di confrontare il campo “nome” di due oggetti Utente
getName
ritorna il valore del campo nome dell’Utente
getIp
ritorna il valore del campo ip dell’Utente
toString
override del metodo toString, chiamato su un oggetto Utente ritorna la stringa formattata nel modo
seguente: “name ip loggato”
Adattatore & AdattatoreChat
Queste classi hanno lo scopo di gestire la chiusura della finestra quando si preme il tasto "X" in alto a
destra. Adattatore controlla se l’utente non è loggato altrimenti effettua il logout prima di uscire.
AdattatoreChat svolge invece le stesse azioni del pulsante chiudi di Chat.
Help
Gestisce l’help in linea di Gossip.
• Diagramma delle Attività
Di seguito viene mostrata un diagramma UML rappresentante l’intera attività che un utente può svolgere
durante l’utilizzo di Gossip. Il diagramma delle attività non si presta in modo eccellente alla modellazione
di alcune parti, come la chiusura, che può essere un’attività svolta in qualsiasi momento.
Fig.2 GOSSIP: Diagramma delle Attività
• Diagramma dei Casi d’uso
Fig.3 GOSSIP: Diagramma dei Casi D’uso
Il diagramma mostra, tutti i casi d’uso che interessano l’attore Utente.
• Narrazione dei Casi d’uso
Nome: Registrazione
Breve descrizione: l'utente si registra
Attori: Utente
Precondizioni: /
Passi Principali:
1 L'utente sceglie un nickname e lo fornisce al sistema.
2 Il sistema verifica l'unicità del nickname.
3 In caso positivo preleva l'IP dell'utente e lo memorizza assieme al nick ed allo stato nel database.
Postcondizioni: Utente Registrato
Situazioni Eccezionali: è impossibile accedere al database degli info degli utenti
Nome: Login
Breve descrizione: L'utente accede al sistema Gossip
Attori: Utente
Precondizioni: L'utente è registrato e non loggato
Passi Principali:
1 L'utente inserisce il nickname per accedere al sistema.
2 Se il nickname è riconoscibile il sistema
2.1 Logga l'utente, modificando il suo stato nel database contenente le info degli utenti e nel database
contente i contatti.
2.2 Sceglie un message server da associare all'utente. Se non c'è nessun message server lo comunica
all'utente altrimenti verifica se ci sono messaggi in entrata non ancora letti e li comunica all'utente.
2.3 Aggiorna lo stato degli utenti presenti nelle liste contatti.
Postcondizioni: L'Utente è loggato
Situazioni Eccezionali: è impossibile accedere al database degli info degli utenti o al database dei contatti
Nome:Logout
Breve descrizione: L'utente effettua il logout
Attori: Utente
Precondizioni: L'utente ha effettuato il login
Passi Principali:
1 L'utente comunica al sistema che vuole effettuare il logout
2 Il sistema cambia lo stato dell'utente nel database contenente le info degli utenti e nel database
contenentei contatti
3 il sistema comunica agli altri client interessati l'avvenuto cambiamento
Postcondizioni: L'utente non è loggato
Situazioni Eccezionali: è impossibile accedere al database degli info degli utenti o al database dei contatti
Nome: AggiungiContattoIn
Breve descrizione: l’utente aggiunge un contatto nella sua lista di contatti di ingresso
Attori: Utente
Precondizioni: L’utente è loggato
Passi Principali:
1 L'utente inserisce il nickname da aggiungere
2 Il sistema controlla se il nick che si vuole aggiungere è di un contatto registrato
2.1 se è registrato controlla se è già stato aggiunto
2.1.1 se è già stato aggiunto informa l’utente
2.1.2 altrimenti aggiunge il contatto ed informa l’utente
Postcondizioni: contatto aggiunto nella lista dei contatti in ingresso
Situazioni Eccezionali: è impossibile accedere al database degli info degli utenti
Nome: AggiungiContattoOut
Breve descrizione: l’utente aggiunge un contatto nella sua lista di contatti di uscita
Attori: Utente
Precondizioni: L’utente è loggato
Passi Principali:
1 L'utente inserisce il nickname da aggiungere
2 Il sistema controlla se il nick che si vuole aggiungere è di un contatto registrato
2.1 se è registrato controlla se l’utente che vuole inserire il contatto nella sua lista contatti di
uscita è presente nella lista contatti di ingresso dell’altro
2.1.1 se non è presente aggiunge il contatto e informa l’utente
2.1.2 altrimenti informa l’utente
Postcondizioni: contatto aggiunto nella lista dei contatti di uscita
Situazioni Eccezionali: è impossibile accedere al database degli info degli utenti o al database dei contatti
Nome: ParlaCon
Breve descrizione: permette la chat con altri contatti.
Attori: Utente
Precondizioni: Utente loggato
Passi Principali:
1 L'utente inserisce il nome del contatto con cui vuole chattare
2 il sistema controlla se il contatto esiste
3 se il contatto è online lancia un interfaccia che permette di comunicare con il contatto selezionato e
instaura con esso una connessione.
4 Se il contatto non esiste il sistema lo comunica all'utente.
Postcondizioni: utente è loggato
Situazioni Eccezionali: 1 contatto non online
2 impossibile instaurare la connessione con il contatto online
Sequenza alternativa eventi : contatto non online
Breve descrizione: L'utente invia un messaggio ad un contatto non online.
Attori: Utente
Precondizioni: L'utente è loggato.
Passi Principali:
1 Il sistema avvia una interfaccia che permette all'utente di comporre un messaggio.
2 L'utente compone un nuovo messaggio.
3 Il sistema invia il messaggio al message server dell'utente mittente.
Postcondizioni: /
Situazioni Eccezionali: non è possibile instaurare una connessione con il server dei messaggi
Diagrammi di sequenza relativi ad ogni caso d’uso
Il nostro obiettivo è quello di mostrare l’evoluzione dell’esecuzione dei thread, i diagrammi di sequenza si
prestano bene per rappresentare ciò, anche se in alcuni casi, la modellazione richiede dei vincoli riguardanti
la sequenza temporale dello svolgimento delle azioni, e modella una sincronizzazione dei thread, poco
conforme alla realtà
Fig.4 GOSSIP: Sequence Diagram Registrazione
Fig.5: Sequence Diagram Login
Fig.6 GOSSIP: Sequence Diagram ParlaCon
Fig.7 GOSSIP: Sequence Diagram AggiungiContattoIn
Fig.8 GOSSIP: Sequence Diagram AggiungiContattoOut
Fig.9 GOSSIP: Sequence Diagram Logout
Architettura del sistema
Fig.10 GOSSIP: L’Architettura
L’architettura implementa i servizi offerti da GOSSIP sfruttando sia il modello client/server che quello
P2P. Comprende un BootStrapServer, un insieme di MessageServers ed un insieme di Servlets associati
agli utenti del sistema (in ambito P2P un servlet è un' entità che usufruisce di servizi ed allo stesso tempo
offre servizi). La Fig. 10 mostra uno schema generale dell'architettura. Presenta due Peer un
BootStrapServer e due MessageServer, naturalmente il numero dei Peer e dei MessageServer è a scopo
puramente esemplificativo. Il BootStrapServer fornisce il servizio di registrazione iniziale degli utenti,
di connessione e di sconnessione dal sistema. Le funzioni dei vari componenti dell’Architettura sono già
state spiegate precedentemente. Diamo una breve descrizione dell’uso dei protocolli effettuato in GOSSIP.
Il Protocollo RMI viene usato nel collegamento tra un Peer ed il BootStrapServer, la comunicazione tra i
due peer viene permessa tramite il protocollo TCP, mentre inizialmente (durante il Login dell’utente) il
BootStrapServer chiede ad ogni message server, in MULTICAST, quante righe contiene il loro file, ed
ognuno a sua volta risponde, in MULTICAST, inviando il proprio numero di righe. Questa scelta permette
la minimizzazione del carico dei MessageServer.
Successivamente, il BootStrapServer invia (tramite il protocollo UDP) al MessageServer che contiene il
numero minore di righe, le informazioni sul Peer. Il MessageServer scelto, chiede in MULTICAST agli
altri se hanno messaggi riguardante quel client, chi li possiede, risponde inviando (sul collegamento
MULTICAST) un pacchetto contenente tutti i messaggi per il dato utente. Dopodichè, al momento
dell’avvenuta connessione del Peer, il MessageServer gli spedisce (tramite UDP) tutti i messaggi.
Dislocazione dei componenti
Fig.11 GOSSIP: Vista Ibrida
La figura, rappresenta una Vista Ibrida, mostra componenti e connettori, con lo scopo di evidenziare la
dislocazione dei componenti sui vari nodi, e il tipo di comunicazione adottata. Nella figura è mostrato solo
un esempio di quello che può essere l’architettura, in quanto gli oggetti sono in forma istanza quindi non
rappresentano situazioni generali, ma situazioni particolari.
Guida per l’amministratore di rete
Funzionalità e servizi del BootStrapServer e dei MessageServer
Il progetto si compone di due parti fondamentali per il giusto funzionamento di tutti i servizi.
Esse sono l’avvio del BootStrapServer e del MessageServer. Senza il BootStrapServer, in pratica, per
l’utente è come se non fosse disponibile nessun servizio e sarebbe impossibile per lui “chattare” con i suoi
amici. Senza il MessageServer, inoltre, l’utente è impossibilitato a utilizzare il servizio di posta elettronica
per gli utenti fuori linea, quindi è bene assicurarsi che sia BootStrapServer che MessageServer siano attivi,
anche sulla stessa macchina, naturalmente si consiglia di dislocarli su due macchine diverse in modo tale
da avere più risorse hardware disponibili. È consigliabile anche attivare vari MessageServer su più
macchine. Attivare un MessageServer su una sola macchina non porterebbe a nulla di buono in quanto
andrebbero ad utilizzare le stesse porte e di conseguenza lancerebbero eccezioni di diversa natura.
L’architettura generale per l’interazione Client-BootStrapServer è basata sulle RPC (Remote Procedure
Call), questo vuol dire che il Client invoca una procedura RPC definita sul server. L’invocazione della
procedura avviene sull’host su cui è in esecuzione il client ma la procedura viene eseguita sull’host su cui è
in esecuzione il server. Il server definisce l’oggetto remoto (BootStrapServer, nel nostro caso), cioè,
definisce un oggetto distribuito (un oggetto i cui metodi possono essere invocati da parte di processi in
esecuzione su hosts remoti), server nel nostro caso, dopodichè crea un legame tra il “nome simbolico di un
oggetto ed il riferimento a quell’oggetto” (nel nostro caso: “BootStrapServer / server”) e lo pubblica
mediante un servizio di tipo registry. Quando il client vuole accedere all’oggetto remoto (per esempio
quando un utente vuole fare la registrazione o il login ecc.) per prima cosa ricerca un riferimento
all’oggetto remoto mediante i servizi offerti dal registry, dopo di che invoca i metodi definiti dall’oggetto
remoto (RMI remote method invocation). Da questo l’importanza di attivare il server che fornisce il
servizio di registrazione di oggetti remoti (registry) prima di aver avviato il BootStrapServer. Al suo
interno il BootStrapServer utilizza un metodo della classe Naming (contente i metodi per la gestione dei
registry), il rebind(), che crea un collegamento tra un nome simbolico (qualsiasi) ed un riferimento
all’oggetto. Se esiste già un collegamento per lo stesso oggetto all’interno dello stesso registry, tale
collegamento viene sovrascritto.
Attivazione del registry RMI
L’attivazione del registry in background si esegue scrivendo la seguente riga:
$> rmiregistry &
Per default, viene creato un registry alla porta 1099, se la porta è già utilizzata viene sollevata una
eccezione, per scegliere esplicitamente una porta si digita il comando
$> rmiregistry numeroporta &
Il client a sua volta, ricerca un riferimento all’oggetto remoto e invoca i metodi dell’oggetto remoto come
fossero metodi locali con l’unica differenza di intercettare RemoteException che potrebbe essere lanciata
da uno qualsiasi dei metodi remoti. Per ricercare un riferimento all’oggetto remoto, il client deve accedere
al registry effettuando il Naming.lookup(registryURL) dove registryURL è una stringa formata in questo
modo: rmi://hostName:portNum/BootStrapServer" e hostName e portNum rappresentano, rispettivamente,
il nome dell’host su cui si trova il BootStrapServer e la porta su cui è attivato il registry. Il riferimento
restituito dal registry è un riferimento ad un oggetto di tipo Object, esso viene castato al tipo definito
nell’interfaccia remota (BootStrapServerInterface).
Nello sviluppo del progetto abbiamo preferito utilizzare RMI sia per l’invocazione client-server
(registrazione, login ecc.) che per quella server-client (notifyMe notifica del verificarsi di un evento)
utilizzando il meccanismo delle callback. In questo modo oltre al server anche il client definisce
un’interfaccia remota (ClientInterface) che definisce i metodi remoti utilizzati dal server per notificare un
evento al client. Il BootStrapServer ha a disposizione ClientInterface e il Client ha a disposizione il
BootStrapServerInterface. Il Client però non registra l’oggetto remoto in un rmiregistry, ma passa un
riferimento a tale oggetto al BootStrapServer.
Attivazione MessageServer & BootStrapServer
Il MessageServer a sua volta deve essere avviato aggiungendo alla riga di comando una stringa che
rappresenta il nome del file su cui si vuole creare la struttura di salvataggio dei messaggi.
Il comando
$> java MessageServer nomefile.txt
lancia un message server e crea un file di nome prova.txt dove, al momento opportuno andrà ad effettuare
operazioni di lettura o di scrittura, a seconda della situazione in cui ci si trova. Qualora si dimenticasse di
associare il file nella riga di comando, viene lanciata un’eccezione che avvisa l’amministratore della
dimenticanza avvenuta.
Il BootStrapServer si attiva con il comando
$> java BootStrapServer
Guida per l’utente Generico
Passi principali:
Prima di usufruire del servizio, devi effettuare una registrazione in cui fornisci al sistema il tuo nickname e
l'indirizzo IP. Il sistema verifica che il nickname non sia stato già scelto da altri utenti ed, in caso
affermativo, registra i tuoi dati in un proprio database. Successivamente, puoi usufruire del servizio
connettendoti al sistema (login) e quindi disconnettendoti dal sistema (logout). Ogni utente è caratterizzato
da uno stato di presenza sulla rete che indica, in ogni istante, se esso è online, cioè ha effettuato il login,
oppure offline. Ogni utente definisce una propria Lista di Contatti di Ingresso, in cui inserisce i nicknames
di tutti i mittenti dai quali è disposto a ricevere messaggi ed una lista di Lista di Contatti di Uscita che
contiene i nicknames di tutti gli utenti a cui intende inviare i messaggi. Prima di inserire un nuovo contatto
C nelle propria lista, l' utente invia il nickname di C a GOSSIP, che verifica l'esistenza di un utente con
quel nickname. Puoi inserire un utente U nella tua lista dei Contatti di Uscita solo se U ti ha
preventivamente inserito nella propria Lista di Contatti di Ingresso.
Quando sei in linea, in ogni momento, conosci lo stato di presenza degli utenti presenti nella tua Lista di
Contatti di Uscita, viene aggiunto un “+” davanti al nickname dell’utente, se è connesso, altrimenti rimane
scritto solo il nickname. Nel caso in cui un utente U modifichi il proprio stato, il sistema notifica tale
cambiamento a tutti gli utenti interessati. Per esempio, se U è presente nella tua Lista di Contatti di Uscita e
sta effettuando il Login, a connessione avvenuta, davanti al suo nome verrà aggiunto il simbolo “+”, questo
per indicare che in quel momento U è in linea.
Dopo esserti connesso al sistema, puoi inviare messaggi ad un qualsiasi altro utente U contenuto nella tua
Lista dei Contatti di Uscita. Nel caso in cui il destinatario del messaggio sia online il messaggio gli viene
recapitato in tempo reale, altrimenti il sistema memorizza il messaggio e lo recapita al destinatario al
momento della sua successiva connessione al sistema. GOSSIP realizza quindi un servizio di Instant
Messaging per gli utenti in linea ed un servizio simile alla Posta Elettronica per gli utenti fuori linea.
Avvio del Client
Per avviare l’interfaccia grafica che ti permette di gestire queste interazioni, devi come prima cosa
compilare il codice, utilizzando Eclipse oppure digitando da shell il comando
$> javac “pathname/nomefile.java”
Genererà un nomefile.class che sarà mandato in esecuzione con il comando
$> java “pathname/nomefile”
Presentazione dell’interfaccia:
L’interfaccia si presenta in questo modo:
Inizialmente i pulsanti abilitati sono solamente
Registrazione e Login, in quanto nessun altra operazione
si può effettuare se non si è prima connessi al sistema. A
Login effettuato, comparirà la possibilità di premere
Logout, ParlaCon, e i due pulsanti +.
Accanto alla scritta Nickname naturalmente andrà
inserito il nickname scelto, ed accanto alla scritta Server
andrà scritto il nome dell’host su cui si trova il
BootStrapServer
(vedere
sezione
Guida
per
l’amministratore di Rete). Il tutto è abbellito da una
simpatica nuvoletta dove verranno notificate tutte le
informazioni riguardo le funzioni disponibili.
“Logout” serve per effettuare la disconnessione dal
sistema.
“Parla con” viene usato per parlare istantaneamente con
un amico o per mandare messaggi offline, servizio
simile alla posta elettronica
I pulsanti “+” consentono di inserire nuovi contatti (in
ingresso o in uscita rispettivamente) nella finestra in cui
si trovano, gli effetti sono stati spiegati precedentemente
Sviluppi futuri:
prendiamo innanzi tutto in esame l’interfaccia grafica, in
futuro è pensabile di migliorarla e renderla più userfriendly. Esaminando i servizi RMI, vediamo che è
facile pensare di implementarne altri permettendo, per
esempio ad un utente di fare delle comunicazioni in conferenza o di fare ricerche su tutti i contatti in linea.
Spostandoci sull’implementazione da noi adottata, si rileva la totale mancanza di sicurezza nella
comunicazione tra due utenti. Inoltre manca anche la possibilità di inserire insieme al proprio nickname,
una password durante la registrazione, impedendo così l’accesso agli utenti non registrati (Es: se un utente
proprietario di un nick è assente, nessun altro può accedere con lo stesso nome). E’ possibile implementare
il trasferimento di file, oltre alla chat, permettendo agli utenti registrati di scambiarsi file di diverso tipo
oltre allo scambio di informazioni in forma testuale. Naturalmente a nostro vantaggio, per l’espansione del
progetto, abbiamo la possibilità di metterlo in rete con licenza opensource-GPL, cosicché ogni utente può
apportare migliorie al progetto dove le ritenga necessarie.
Bibliografia
Lucidi visti a lezione durante il corso di Laboratorio Programmazione di Rete, tenuto dalla prof. Laura
Ricci supportata dal prof. Paolo Mori, dell’anno scolastico 2006/2007
J. Arlow, I. Neustadt, UML 2 e Unified Process, Seconda Edizione italiana, McGraw-Hill, 2006
O.Reilly, Java Network Programming 2
Si ringraziano le professoresse Laura Ricci e Laura Semini per la loro disponibilità.