Chat HELP DESK su HTTP
1
FACOLTÀ DI INGEGNERIA
Tesi di laurea in Ingegneria Informatica
Università degli Studi di Roma -La Sapienza- a.a. 2003-2004
sessione estiva maggio 2004
Chat HELP DESK su HTTP
Supino Antonello Relatore:
Prof. Luca Iocchi Tutor:
Prof. Andrea Vitaletti
Chat HELP DESK su HTTP
3
IINNDDIICCEE 1 INTRODUZIONE................................................................................................................................................... 5
1.1 OBBIETTIVI....................................................................................................................................................... 5 1.2 DESCRIZIONE DEL PROGETTO ........................................................................................................................... 5 1.3 DIAGRAMMA DELLE CLASSI.............................................................................................................................. 6 1.4 DESCRIZIONE DELLE FUNZIONALITÀ ............................................................................................................... 11 1.5 DESCRIZIONE DEL MATERIALE REALIZZATO.................................................................................................... 13
2 PRINCIPI E TECNOLOGIE UTILIZZATE PER LA REALIZZAZIONE DELL’APPLICAZIONE ....... 14 2.1 UTILIZZO DELL’ARCHITETTURA CLIENT/SERVER ............................................................................................ 14 2.2 PRINCIPI UTILIZZATI PER LA PROGRAMMAZIONE DI RETE ............................................................................... 15 2.3 IL LINGUAGGIO JAVA ORIENTATO AGLI OGGETTI............................................................................................ 18 2.4 THREAD IN JAVA ............................................................................................................................................ 19
2.4.1 Modello di vita a quattro stati .................................................................................................................. 20 2.4.2 Adozione del multithread .......................................................................................................................... 22 2.4.3 Sincronizzazione ....................................................................................................................................... 22
2.5 GESTIONE DELLE ECCEZIONI .......................................................................................................................... 23 2.6 UTILIZZO DI UN DATABASE............................................................................................................................. 25 2.7 INTERFACCIA GRAFICA ................................................................................................................................... 28 2.8 VISUALIZZATORE DI IMMAGINI....................................................................................................................... 30 2.9 I SUONI ........................................................................................................................................................... 31 2.10 SELETTORE DI FILES E INDICATORI DI AVANZAMENTO.................................................................................... 32
3 IL DIALOGO TRA CLIENT E SERVER.......................................................................................................... 33 3.1 SCAMBIO DI DATI ATTRAVERSO LA RETE ........................................................................................................ 33 3.2 IL CODICE CHE IDENTIFICA IL TIPO DEI MESSAGGI........................................................................................... 36
4 L’APPLICAZIONE CLIENT.............................................................................................................................. 41 4.1 LA FASE DI INIZIALIZZAZIONE ........................................................................................................................ 41 4.2 REGISTRAZIONE E DEREGISTRAZIONE............................................................................................................ 42 4.3 GESTIONE DELLE OPZIONI DI CONNESSIONE AL SERVER ................................................................................. 42 4.4 LA FASE DI LOGIN .......................................................................................................................................... 43 4.5 IL MENU PRINCIPALE ...................................................................................................................................... 44 4.6 LA CONVERSAZIONE PRIVATA ........................................................................................................................ 46
4.6.1 Invio di un messaggio di testo................................................................................................................... 47 4.6.2 FileChooser e ImageChooser ................................................................................................................... 48 4.6.3 Invio e ricezione di un file......................................................................................................................... 49 4.6.4 Invio e ricezione di una slide .................................................................................................................... 50 4.6.5 Progress Monitor...................................................................................................................................... 50 4.6.6 Disegno sulla Lavagna ............................................................................................................................. 51 4.6.7 Cancellazione della Lavagna.................................................................................................................... 52
4.7 LA CONVERSAZIONE MULTIUTENTE NELLE STANZE........................................................................................ 52 4.7.1 Invio e ricezione di un messaggio di testo ................................................................................................ 53 4.7.2 Disegno sulla Lavagna ............................................................................................................................. 54 4.7.3 Cancellazione della Lavagna.................................................................................................................... 54
5 L’APPLICAZIONE SERVER............................................................................................................................. 55 5.1 LA FASE DI INIZIALIZZAZIONE ........................................................................................................................ 55 5.2 IL DATABASE ONLINE..................................................................................................................................... 56 5.3 LO SMISTAMENTO DELLE CONNESSIONI ENTRANTI......................................................................................... 57
5.3.1 Registrazione e Deregistrazione ............................................................................................................... 57 5.3.2 Login e Logout di un Client ...................................................................................................................... 58 5.3.3 Messaggi delle conversazioni private ....................................................................................................... 58 5.3.4 Messaggi delle conversazioni multiutente nelle stanze............................................................................. 59 5.3.5 Disegni e cancellazione delle lavagne ...................................................................................................... 61 5.3.6 Ricezione e inoltro dei files....................................................................................................................... 61
Chat HELP DESK su HTTP
4
5.3.7 Ricezione e inoltro delle slides ................................................................................................................. 62 5.4 PINGING E DISCONNESSIONE AUTOMATICA PER TIMEOUT ............................................................................... 62 5.5 LO SHUTDOWN DEL SERVER .......................................................................................................................... 63
6 LA DOCUMENTAZIONE................................................................................................................................... 64 7 BREVE MANUALE PER L’USO ....................................................................................................................... 65
7.1 ISTRUZIONI PER LA CONFIGURAZIONE E L’UTILIZZO ....................................................................................... 65 7.2 UN CASO DI TEST PER L’APPLICAZIONE........................................................................................................... 66 7.3 REQUISITI MINIMI DI SISTEMA ........................................................................................................................ 68
8 PROBLEMI E SOLUZIONI................................................................................................................................ 70 9 CONCLUSIONI .................................................................................................................................................... 73
9.1.1 Statistiche del progetto ............................................................................................................................. 73 9.1.2 Ringraziamenti.......................................................................................................................................... 73 9.1.3 Bibliografia............................................................................................................................................... 74
Chat HELP DESK su HTTP
5
11 IINNTTRROODDUUZZIIOONNEE
11..11 OOBBBBIIEETTTTIIVVII Questo progetto è stato realizzato per consentire un dialogo multimediale tra due o più utenti.
Spesso capita che uno studente abbia bisogno di ulteriori chiarimenti su argomenti svolti in
aula durante le lezioni di un corso e spesso l’unico modo di ricevere chiarimenti è quello di
recarsi di persona nell’ufficio del professore.
Il primo obbiettivo che questo software si propone è fornire un’interfaccia amichevole e fun-
zionale che riproduca, in tempo reale attraverso due computer collegati ad Internet, gli stessi
strumenti didattici di cui due persone dispongono quando sono faccia a faccia: possibilità di
dialogare e vedere insieme immagini su cui disegnare, un foglio di carta virtuale su cui scri-
vere con una penna, possibilità di scambiare files e documenti.
Il secondo obbiettivo è riuscire ad instaurare il collegamento via Internet tra due o più utenti
tenendo conto che nella rete ci sono diversi ostacoli da superare: Firewalls, sottoreti con IP
privati, Server Proxy di vario tipo, porte filtrate ecc.
L’utilizzo di questa applicazione permette di risparmiare il tempo e il denaro che due persone
devono impiegare per incontrarsi fisicamente e di dialogare comodamente anche da casa
propria. Inoltre si rende possibile una conversazione avanzata anche tra persone che magari
non potrebbero mai incontrarsi fisicamente se non con un dispendio spropositato di risorse
quali: persone disabili, persone che sono geograficamente troppo distanti tra di loro ecc.
11..22 DDEESSCCRRIIZZIIOONNEE DDEELL PPRROOGGEETTTTOO Questo progetto consiste in una “Chat” con funzionalità avanzate ed è basato su
un’architettura Client/Server. I Clients possono essere eseguiti su qualunque computer della
rete, anche sullo stesso computer su cui gira il Server. Il Server deve essere mandato in ese-
cuzione su una macchina il cui indirizzo IP sia visibile a tutti i Client: il server visibile a tutti
i computer della sua rete e alle sottoreti direttamente connessa ad essa. In particolare se il
server ha un indirizzo internet IP Pubblico allora è visibile in tutto il mondo in tutte le sotto-
reti con accesso a internet. Tuttavia è possibile utilizzare questo software su una qualunque
sottorete.
Il linguaggio di programmazione utilizzato è il Java. Per rendere più gradevole e comprensi-
bile l’interfaccia utente sono state utilizzate delle immagini, anche di tipo animato, e dei suo-
ni che accompagnano gli eventi che si verificano durante la normale esecuzione del software.
Chat HELP DESK su HTTP
6
Grazie all’integrazione di Java col sistema operativo è possibile eseguire la selezione dei files
e delle slides da inviare e visualizzare con una pratica interfaccia utente che permette di e-
splorare tutte le cartelle del disco rigido locale. I files e le slides ricevute sono immagazzinati
e catalogati in sottocartelle del Client aventi il nome dell’utente dal quale sono stati ricevuti.
Durante il trasferimento vengono visualizzate delle barre di avanzamento che danno anche la
possibilità di interrompere il trasferimento dei files e delle slides in qualunque momento. È
possibile mantenere aperti contemporaneamente più trasferimenti sia in ingresso che in usci-
ta, continuando la conversazione.
Il visualizzatore di immagini è compatibile con immagini in formato: Jpeg, Gif, Tiff e Gif a-
nimate.
Sia il Client che il Server hanno un architettura multithread: ciò garantisce una notevole ro-
bustezza da entrambi i lati. Inoltre viene assegnata una maggiore priorità alle conversazioni e
alla lavagna, in secondo piano vengono conferite risorse al trasferimento delle slides e infine
vengono date risorse con la minima priorità al trasferimento dei files.
11..33 DDIIAAGGRRAAMMMMAA DDEELLLLEE CCLLAASSSSII Il diagramma delle classi è stato generato in modo completo e dettagliato utilizzando Visual
Paradigm UML 3.0.
Poiché il numero delle classi di questa applicazione è molto elevato i files di immagine rap-
presentanti il diagramma delle classi sono di grandi dimensioni. Nonostante abbia diviso il
tutto in sottodiagrammi questi, senza zoom, sembrano incomprensibili. Perciò non mi è pos-
sibile importare tali diagrammi in questo documento senza occupare almeno 100 pagine. Per
una loro consultazione si rimanda direttamente al materiale in formato ipertesto, files html e
immagini formato Jpeg, contenuto nella sottocartella “Class Diagrams” della cartella “Im-
plementazione”.
Tuttavia ho deciso di riportare alcuni diagrammi delle classi, fatti da me, ovviamente più
semplici, ma che possono dare un’idea della struttura delle applicazioni Client e Server. In
questi diagrammi sono state omesse le funzioni e alcune classi meno importanti. Le frecce
mostrano alcune delle interazioni tra le classi Java. Lo scopo è di ripercorrere i principali
flussi di dati, scambiati tra Client e Server, e il percorso che essi compiono passando da clas-
se in classe ma anche sulla rete.
Per iniziare ho deciso di riportare due Packages Diagram. In questo, modo partendo da una
visione panoramica e globale dell’elaborato, scenderemo man mano sempre più nel dettaglio.
Chat HELP DESK su HTTP
7
I Packages Diagram descrivono a grandi linee le interazioni tra la classi Java contenute al lo-
ro interno.
Il diagramma dei packages del Server:
Il diagramma dei packages del Client:
Adesso siamo pronti per visionare i diagrammi delle classi. Vorrei precisare che le linee ros-
se rappresentano i confini tra l’interno dei processi Client e Server e la rete.
Le frecce più grosse simboleggiano dei collegamenti tra vari diagrammi e in taluni casi anche
lo scambio di dati attraverso la rete. La freccia verde invece simboleggia la MainConnection.
gui exception
net serverhelpdesk
exception
net clienthelpdesk gui
filechooser audioplayer
progressmonitor
Chat HELP DESK su HTTP
8
Il diagramma delle classi del Server:
raidayServerHelpDesk
RaidayServer
ClientConnectionDeliver
SingleTalkManager SlideManager MultiTalkManager
ServerConnectionCenter
net
ServerConnectionHandler PingServer
FileManager
Database
OJDBCConnection
OnlineDB
Chat HELP DESK su HTTP
9
Il diagramma delle classi del Client:
raidayClientHelpDesk
RaidayClient
ClientConnectionHandler MainConnectionListner
ClientConnectionDeliver
FileProcessor MessageProcessor SlideProcessor
TalkSingolo TalkMultiUtente
TalkReciver
SendMessage SendMultipleMessage
ClientConnectionCenter
net
Chat HELP DESK su HTTP
10
Prima vorrei precisare che le classi XxxxxConnectionCenter e YyyyyConnectionHandler rap-
presentano ClientConnectionCenter, ServerConnectionCenter, ClientConnectionHandler e
ServerConnectionHandler. Quest’abbreviazione è utile poiché il package net e le classi che
lo compongono sono le medesime sia nell’applicazione Client che nell’applicazione Server.
Diagramma delle classi del package net:
Un’altra cosa che è meglio chiarire è il diagramma delle classi che costituiscono l’interfaccia
grafica del Client. Questa volta le frecce simboleggiano semplicemente una relazione tra
classi Java.
YyyyyConnectionHandler
net Connection
ProxyInfo
XxxxxConnectionCenter
Proxy
DirectConnection HttpConnection
Proxy
SocksConnection
Chat HELP DESK su HTTP
11
Diagramma delle classi del package gui del Client:
Gui(Client) ClientMainFrame
MyJdialog
MyJFCUtente
RaidayClient
MyJFLogin
MyJFOpzioni
MyJFRegistrazione
TalkSingolo MyJFTalkSingolo
11..44 DDEESSCCRRIIZZIIOONNEE DDEELLLLEE FFUUNNZZIIOONNAALLIITTÀÀ Le funzionalità sviluppate sono:
Interfaccia grafica animata
Registrazione nuovo utente presso il server
Deregistrazione utente presso il server
Pannello Opzioni di Collegamento
Collegamento diretto al server tramite IP pubblico e privato
Collegamento proxy http al server tramite IP pubblico e privato
MyJFTalkMultiUtente
ImageBoard
TalkMultiutente
Chat HELP DESK su HTTP
12
Collegamento proxy Socks 4 e 5 al server tramite IP pubblico e privato
Autenticazione tramite Username e Password
Possibilità di accedere nuovamente come altro utente senza chiudere il client
Conversazione in modalità privata
Conversazione in modalità multiutente: stanze
Visualizzazione degli utenti connessi in una stanza e possibilità di contattarli ra-
pidamente con doppio click del mouse
Visualizzazione di tutti gli utenti connessi al server
Visualizzazione d i tutte le Stanze esistenti e aperte
Accedere ad una stanza esistente
Creare una nuova stanza
Lavagna virtuale remota dove è possibile disegnare col mouse e far apparire il suo
contenuto agli altri utenti sia nelle conversazioni private che nelle stanze multiu-
tente.
Pulizia simultanea di tutte le lavagne collegate tra loro
Visualizzare e inviare files in formato immagine come sfondo su tutte le lavagne
tra loro collegate sulle quali è possibile continuare a disegnare
Ricevere e visualizzare files in formato immagine come sfondo della lavagna
Inviare e ricevere files di qualunque dimensione
Selezionare i files da inviare da qualunque locazione del disco rigido locale con
una comoda interfaccia grafica
Selezionare le slides da inviare da qualunque locazione del disco rigido locale con
una comoda interfaccia grafica che filtra solo i files di tipo immagine supportato e
ne visualizza un’anteprima
Effetti sonori che accompagnano gli eventi di normale funzionamento del Client
Connessione simultanea fino ad un massimo 100 utenti sul Server
Recupero automatico e invisibile in seguito a malfunzionamenti ed eccezioni sia
per il Client che per il Server
Gestione dei timeout
Disconnessione automatica dal server dei Clients caduti
Registrazione dei dati di login in un file formato MS Access Database su disco ri-
gido del Server
Assegnazione intelligente delle risorse del sistema ai vari thread del Client e del
Server
Chat HELP DESK su HTTP
13
Chiusura del Client e disconnessione dal Server
Chiusura del Server
Tutte queste funzioni saranno descritte in seguito quando si parlerà anche dei dettagli imple-
mentativi che hanno reso possibile la loro realizzazione.
11..55 DDEESSCCRRIIZZIIOONNEE DDEELL MMAATTEERRIIAALLEE RREEAALLIIZZZZAATTOO Nella cartella principale vi sono dei files eseguibili che permettono di eliminare istantanea-
mente tutti i files ricevuti dal Client e di avviare Client e Server sia modalità applicazione sia
debug. Vi sono inoltre tre sottocartelle: “Api”, “Client” e “Server”.
La sottocartella “Api” contiene un altro file batch che genera la documentazione in formato
Javadoc. La documentazione riguardante separatamente Client e Server è contenuta nelle due
sottocartelle omonime della cartella Api. La documentazione può essere consultata aprendo
con un web browser(es. Internet Explorer 6) i files index.html.
La sottocartella “Class Diagrams” contiene due immagini in formato Jpeg che rappresentano
i diagrammi delle classi del Client e del Server, alcuni files di progetto formato Visual Para-
digm UML 3.0, e due sottocartelle “Client” e “Server”. Queste ultime contengono i dia-
grammi delle classi, suddivisi in sotto diagrammi, minuziosamente commentati da un iperte-
sto html.
La sottocartella “Client” contiene il codice sorgente fatto di files Java organizzati in packa-
ges, il progetto JCreator per il Client e una sottocartella “classes”: l’applicazione Client.
Quest’ultima contiene i files compilati .class(organizzati in packages) in byte-code, le imma-
gini dell’interfaccia utente in “gui”, i suoni dell’applicazione in “sounds”, le icone dei file
immagine in “filechooser”, due cartelle “images” e “files” contenente alcune slides e files di
esempio da visualizzare e inviare, le sottocartelle “rcvimages” e “rcvfiles” in cui vengono
immagazzinati i files ricevuti.
La sottocartella “Server” contiene il codice sorgente fatto di files Java organizzati in packa-
ges, il progetto JCreator per il Server e una sottocartella “classes”: l’applicazione Server.
Quest’ultima contiene i files compilati .class(organizzati in packages) in byte-code e le im-
magini dell’interfaccia utente in “gui”.
Chat HELP DESK su HTTP
14
22 PPRRIINNCCIIPPII EE TTEECCNNOOLLOOGGIIEE UUTTIILLIIZZZZAATTEE PPEERR LLAA RREEAALLIIZZ--ZZAAZZIIOONNEE DDEELLLL’’AAPPPPLLIICCAAZZIIOONNEE
22..11 UUTTIILLIIZZZZOO DDEELLLL’’AARRCCHHIITTEETTTTUURRAA CCLLIIEENNTT//SSEERRVVEERR Il modello client-server è l'architettura tipica su cui si basa la maggior parte dei sistemi di
comunicazione. Secondo tale modello un Server è un software che risiede su di un computer
collegato in rete e che eroga un particolare servizio. Gli utenti per usufruire dei servizi offerti
da un Server devono utilizzare un particolare software, il Client, che è in grado di inoltrare le
richieste al Server. Naturalmente il Client può risiedere sulla stessa macchina del Server, in
questo caso si parla di processo locale, oppure risiedere su un'altra macchina collegata in rete
con la macchina del il Server, in questo caso parliamo di processo remoto.
La scelta di questo modello è stata
forzata: poiché può darsi che alcuni
Clients si trovino in reti con IP privato
oppure protette da firewalls questi non
possono in alcun modo accettare
connessioni dall’esterno. È
indispensabile quindi che questi
mantengano un canale di comunicazione
aperto verso un server, una macchina
visibile a tutti, attraverso il quale questi
vengono contattati o a cui si richiedono
ulteriori connessioni. In questo caso il
server deve fare ancora di più: per
consentire il funzionamento in ogni con-
dizione il collegamento peer to peer non
viene mai utilizzato e tutti i dati inviati da qualunque Client verso qualunque Client devono
passare per il Server. Questo è l’unico modo per permettere a qualunque computer di utiliz-
zare un programma di Chat come questo quando il Client si trova in sottoreti protette oppure
ci sono dei firewalls aziendali che vogliono evitare l’utilizzo di tali applicazioni. Tuttavia ci
sono anche dei lati negativi: aumenta il tempo di latenza dei dati nella rete e soprattutto la ve-
locità di trasferimento composita di tutti gli utenti che è limitata dalla sola velocità del server.
L’applicazione Server deve essere mandata in esecuzione necessariamente su un computer
visibile a tutti, con un processore potente, tanta ram e soprattutto una grande banda.
Chat HELP DESK su HTTP
15
Un altro motivo per aver adottato questa architettura è che si ritiene necessario avere a dispo-
sizione una macchina stabile e sempre on-line che mantenga al sicuro i dati di login e coordi-
ni il tutto avendo una visione globale.
22..22 PPRRIINNCCIIPPII UUTTIILLIIZZZZAATTII PPEERR LLAA PPRROOGGRRAAMMMMAAZZIIOONNEE DDII RREETTEE La base di funzionamento a livello di rete è il protocollo TCP. Questo permette di trasmettere
dei dati in modo affidabile e senza errori attraverso una rete. Java implementa i Socket uti-
lizzando proprio questo protocollo.
Sul protocollo TCP si appoggia il protocollo IP. In una rete ogni computer è identificato da
un indirizzo IP. Se un computer però si trova in una sottorete allora il suo indirizzo IP è rela-
tivo a una subnetmask tipo 255.255.255.0 e ciò può creare problemi di istradamento da una
rete esterna verso l’interno di
questa.
Inoltre su ogni computer possono
essere contemporaneamente in
esecuzione uno o più processi. La Porta identifica il processo col quale si vuole comunicare.
Un socket è dato dalla terna: protocollo, ip, porta. Esso permette di identificare in modo non
equivoco un particolare processo che gira su una qualunque macchina della rete.
Per stabilire una connessione
remota tra due computer è
indispensabile che uno dei due, il
server, apra una serversoket
e si metta in ascolto su una porta,
in questo caso la porta 80(http). Poi un altro computer, il client, apre una socket e verso
l’indirizzo IP del server e verso la porta 80. Il client richiede al sistema una connessione. A
questo scopo viene aperta dal sistema una porta, il cui numero, però, non deve essere neces-
sariamente fissato. Infatti, la comunicazione può comunque avvenire perché nel pacchetto
inviato dal client al server è specificato, oltre all’indirizzo IP della macchina remota (in ma-
niera tale da consentire il corretto instradamento del pacchetto sulla rete IP) e alla porta su
cui gira il processo server, anche la porta aperta sulla macchina client appositamente per con-
sentire questa comunicazione. Il processo server in ascolto sulla porta specificata accetta la
connessione entrante e apre una nuova socket per comunicare direttamente con il client. La
serverSocket, infatti, ha il solo scopo di raccogliere le richieste di connessione entranti.
Chat HELP DESK su HTTP
16
Nel nostro caso(multithread) la serverSocket ritorna subito in ascolto sulla porta 80
mentre il nuovo socket viene affidato a un thread dedicato che può subito iniziare il dialogo
con il client. A questo punto è stato creato un canale di comunicazione stabile e affidabile su
cui inviare e ricevere dati.
In particolare in Java i socket sono degli oggetti dai quali è possibile prelevare dei canali di
ingresso e di uscita su cui invocare metodi per la lettura e la scrittura di informazioni.
Per leggere e scrivere dati su un socket, bisogna ottenere dall’oggetto Socket l’inputStream e
l’outputStream, attraverso l’invocazione rispettivamente dei metodi getInputStream()
e getOutputStream(). Ottenuti gli streams, cioè gli accessi ai flussi di dati, Java offre
una molteplicità di classi che gestiscono l’I/O. La scelta fra queste, viene fatta a secondo del
tipo di dati che si scambiano. In generale quando si vuole trasmettere dati in formato stringa
si possono utilizzare il BufferedReader e il PrintWriter; quando c’è bisogno di tra-
smettere files o immagini si devono utilizzare direttamente la read() e la write() rispet-
tivamente sull’InputStream e sull’OutputStream per trasmettere byte in formato
grezzo.
Grazie a questi strumenti, attraverso gli streams dei socket su TCP, le applicazioni client e
server si scambiano dati in modo sincronizzato utilizzando un particolare protocollo di co-
municazione e permettono agli utenti di chattare, scambiarsi files, immagini, ecc.
Tuttavia come detto prima può capitare che il Client e il Server non possano “dialogare” di-
rettamente tra di loro. Spesso tra di loro c’è di mezzo un server proxy oppure il Client non è
“visibile” al server e non può essere mai contattato direttamente.
Nel caso in cui il Client sia “visibile” al server questo ascolta le connessioni entranti sulla
porta 80(http). Quindi dal Client vengono creati socket che puntano direttamente alla porta
80 del Server e dal Server vengono creati socket che puntano direttamente alla porta 80 del
Client
Se tra il client e il server c’è un proxy server, quale che sia di tipo http, socks 4 o 5, ogni vol-
ta che il Client desideri contattare il Server o viceversa viene contattato il server proxy con
uno specifico protocollo di comunicazione e gli viene chiesto di stabilire tramite esso una
connessione verso il Server o verso il Client. In pratica il server proxy fa da ponte tra Client e
Server ma una volta instaurata una connessione attraverso esso, il canale del socket funziona
allo stesso modo di una connessione diretta. Quindi dal Client vengono creati socket verso il
server proxy che a sua volta crea socket che puntano direttamente alla porta 80 del Server.
Dal Server vengono creati socket verso il server proxy che a sua volta crea socket che punta-
Chat HELP DESK su HTTP
17
no direttamente alla porta 80 del Client. Internamente al server proxy il socket e in ingresso e
quello in uscita vengono collegati ed è come se la connessione fosse diretta.
Nel caso in cui il Client “non sia visibile” al server, e quindi ha un “ip privato” è inutile che
questo ascolti le connessioni entranti sulla porta 80(http). Al momento del collegamento il
Client crea una connessione primaria, la mainConnection, verso il server che rimane a-
perta per tutta la sessione. Il Client allora inizia ad ascoltare eventuali richieste del server su
questa connessione. Quando il Server ha bisogno di contattare il Client questo manda la ri-
chiesta al Client sulla mainConnection. A questo punto è il Client che crea una nuova
connessione verso il server ma, una volta creato il socket, è la stessa identica cosa sia che la
connessine l’abbia creata il client, sia che l’abbia creata il server.
Nel caso in cui il Client “non sia visibile” al server e tra il client e il server c’è un proxy
server, quale che sia di tipo Http, Socks 4 o 5, ogni volta che il Client desideri contattare il
Server viene contattato il server proxy con uno specifico protocollo di comunicazione e gli
viene chiesto di stabilire tramite esso una connessione verso il Server. Quando il Server ha
bisogno di contattare il Client questo manda la richiesta al Client sulla mainConnection.
A questo punto è il Client che crea una nuova connessione tramite proxy server e poi tutto
funziona come descritto sopra.
I server Socks 4 e 5 sono dedicati alla funzione di ponte tra un cliente un server, da una sotto-
rete a una rete esterna, ma non è detto che questi siano presenti poiché richiedono computer
dedicati e molta banda. Invece in una rete è sempre permesso di navigare in Internet e quindi
mandare e ricevere connessioni sulla porta 80, quella utilizzata dalle mie applicazioni Client
e Server.
Chat HELP DESK su HTTP
18
Nel caso peggiore la rete può avere un IP privato, ed essere completamente chiusa verso
l’esterno permettendo la navigazione in internet attraverso un proxy server http. In questo ca-
so il Client, utilizzando la CONNECT, riesce a creare dei “tunnel http 1.1” attraverso il proxy
server creando attraverso essi dei canali socket stabili e permanenti attraverso i quali inviare
e ricevere dati. Il proxy http server verrà sicuramente ingannato e creerà per noi la connes-
sione verso la mia applicazione Server che è in ascolto proprio sulla porta 80, quella di un
vero web server.
In conclusione è possibile fornire il servizio di Chat Help Desk praticamente in ogni caso su-
perando tutti gli ostacoli che la rete oppone, ingannando il firewall e il proxy, vanificando
ogni tentativo che un amministratore di rete malizioso potrebbe mettere in atto per impedire
l’utilizzo di un servizio del genere.
22..33 IILL LLIINNGGUUAAGGGGIIOO JJAAVVAA OORRIIEENNTTAATTOO AAGGLLII OOGGGGEETTTTII Il linguaggio di programmazione utilizzato per l’implementazione di questo progetto è il
Java. Infatti questo linguaggio di programmazione orientato agli oggetti sviluppato da Sun è
stato al centro del nostro corso di laurea. Java è particolarmente adatto allo sviluppo di appli-
cazioni fruibili via Internet ma può essere ugualmente usato per sviluppare applicazioni di ti-
po tradizionale.
È proprio in Java che ho appreso le principali tecniche di programmazione che sono ormai
diventate pane quotidiano. Una volta scoperti i suoi segreti questo linguaggio di alto livello
mi ha permesso di realizzare da solo un’applicazione come questa, mezzo megabyte di codi-
ce nel giro di un mese, da solo e lavorandoci saltuariamente.
La scelta del Java, oltre ai fini didattici, è stata quindi catalizzata dall’abbondanza dei metodi
di libreria, dall’ottima documentazione e dalla facilità d’uso e riuso del codice.
Una volta capito il meccanismo fare un programma è un po’ come parlare in
inglese ad una persona. Infatti la programmazione ad oggetti si sta sempre più diffondendo
nel mondo dell’informatica, in quanto offre al programmatore una visuale, che si avvicina
maggiormente ai processi cognitivi umani.
Mentre nella programmazione imperativa, l'enfasi viene posta nella progettazione e nella
scrittura del procedimento con il quale, a partire dai dati in ingresso, si producono i risultati
nella programmazione orientata ad oggetti, l'enfasi viene posta nella progettazione di un mo-
dello del dominio di applicazione.
Un oggetto è una rappresentazione di un oggetto del mondo reale, o di un concetto. Nella fa-
se di progettazione si individuano gli oggetti rilevanti, e per ogni oggetto si identifica la sua
Chat HELP DESK su HTTP
19
struttura e le sue funzionalità. Ogni oggetto ha un proprio stato, e gli oggetti interagiscono
quando un oggetto attiva una funzionalità di un altro oggetto. L'effetto che ne consegue può
essere un cambio di stato, la creazione di altri oggetti, la attivazione di altre funzionalità dello
stesso oggetto o di altri oggetti.
Gli oggetti sono raggruppati in classi: ogni classe rappresenta un insieme di oggetti simili per
struttura e funzionalità. La relazione di sottoinsieme viene modellata con la relazione di ere-
ditarietà tra le classi. Per ottenere il massimo dal paradigma ad oggetti è necessario com-
prenderlo fino in fondo, un suo uso errato può vanificare tutti i benefici teoricamente otteni-
bili da esso.
La programmazione orientata agli oggetti si basa su tre concetti fondamentali Incapsulamen-
to, Ereditarietà, Polimorfismo. Il polimorfismo è il meccanismo grazie al quale un singolo
nome di operazione o di attributo può essere definito per più di una classe e può assumere
diverse implementazioni in ciascuna di quelle classi. Il polimorfismo è anche la proprietà per
mezzo della quale un attributo o una variabile può puntare a oggetti di diverse classi in diver-
si momenti. L'ereditarietà è il meccanismo tramite il quale una classe ha implicitamente defi-
niti tutti gli attributi e operazioni di un’ altra classe. Se la classe B eredita dalla classe A, A
viene detta superclasse di B, mentre B viene detta sottoclasse di A. L’incapsulamento è il
raggruppamento di idee correlate in un’unica unità cui è possibile fare riferimento con un
singolo nome. In particolare in un linguaggio orientato agli oggetti l'incapsulamento si ha
quando le operazioni e gli attributi che rappresentano lo stato vengono raccolti in un tipo di
oggetto in modo che lo stato sia accessibile o modificabile solo attraverso l'interfaccia fornita
dall'incapsulamento.
L’adozione di Java ha permesso di aumentare anche la portabilità del software, cioè la capa-
cità di far funzionare l’applicazione su un numero notevole di piattaforme differenti. Un sor-
gente Java è compilato in formato byte-code, una forma molto simile al linguaggio macchi-
na, ma non specifica per una particolare architettura o sistema operativo. Uno stesso file
byte-code è eseguibile su architetture diverse purché abbiano installata la Java Virtual Ma-
chine.
22..44 TTHHRREEAADD IINN JJAAVVAA In un programma l’anima, ossia il suo codice in esecuzione, è detto processo o task. Un pro-
cesso è un flusso sequenziale di istruzioni che vengono eseguite dal processore. Spesso risul-
ta indispensabile dover dividere il processo in due o più flussi paralleli di istruzioni sequen-
ziali detti threads. Tuttavia in un computer di solito c’è un solo processore e il parallelismo di
Chat HELP DESK su HTTP
20
processi e thread viene simulato da uno Scheduler time-sliced. Naturalmente i programmi
Java devono prescindere dall’algoritmo di
schedulazione sottostante e il flusso di
esecuzione deve essere controllato da
meccanismi di sincronizzazione tra i thread che condividono le stesse risorse. Il discorso del-
la sincronizzazione verrà discusso approfonditamente in seguito.
Ogni Thread è caratterizzato da: un corpo(thread body), uno stato(thread state), una priori-
tà(thread priority), un gruppo di appartenenza(thread group).
Il thread body è fatto dalle operazioni che il thread deve eseguire nel metodo
run()specificate in forma di codice.
Il thread state viene descritto specificamente in seguito.
La thread priority indica il valore di probabilità relativa secondo il quale ogni thread verrà
scelto dallo Scheduler, tra i thread nello stato Runnable, per essere messo nello stato Run-
ning. Ogni thread, in Java, eredita la priorità della classe che lo crea. La priorità di un thread
corrisponde a un valore intero compreso tra MIN_PRIORITY e MAX_PRIORITY, cioè tra
1 e 10. È possibile cambiare la priorità di un thread col metodo setPriority(int).
Ogni thread è membro di un thread group, che va specificato al momento della creazione, ed
ogni operazione attivata sul gruppo si ripercuote su tutti i suoi thread membri.
2.4.1 MODELLO DI VITA A QUATTRO STATI Per supportare il multithreaded, Java possiede un proprio modello a stati(New Thread,
Runnable, Not Runnable, Dead), riportato in figura:
Questo, unitamente a un insieme di funzioni di libreria predefinite, comporta un livello
di astrazione molto elevato permette di gestire i thread senza conoscere il reale funzio-
namento del sottostante Sistema Operativo e dello Scheduler.
Chat HELP DESK su HTTP
21
Ricordando che Java è un linguaggio ad oggetti, tutto deve iniziare con la creazione di
un oggetto Thread. Inizialmente deve essere eseguita l’operazione Thead nuovo-
Thread = new Thread(); e fin qui non vengono allocate risorse poiché lo
Scheduler non sa ancora della sua esistenza. Quando il thread viene avviato con
l’invocazione del metodo Start() sull’oggetto nuovoThread vengono allocate le
risorse necessarie nel sistema, viene inserito il nuovo thread nel meccanismo di Sche-
duler e viene chiamato il metodo run() che causa la biforcazione del flusso di istru-
zioni a livello di Scheduler del sistema operativo. A questo punto il thread passa nello
stato Runnable. Poiché di solito si utilizza un sistema monoprocessore solo un thread
alla volta può essere Running. Lo Scheduler fa si che virtualmente tutti i thread Run-
nable siano Running. L’istruzione yield(), invocata sull’oggetto nuovoThread,
provoca la temporanea sospensione del thread in corso, cosicché lo Scheduler può ce-
dere le risorse di calcolo della CPU ad altri eventuali Thread Runnable, che potrebbero
così divenire Running.
Lo stato Not Runnable è invece lo stato in cui il thread fa parte ancora del sistema, ma
è in attesa di ricevere il possesso della CPU. Il passaggio da Runnable a Not Runnable
può avvenire per quattro motivi diversi:
1) suspend()
2) sleep(tempo in millisecondi)
3) wait() - Il thread aspetta una condizione variabile.
4) operazione di I/O bloccante
Il passaggio da Not Runnable a Runnable può avvenire anche esso per quattro motivi
rispecchiando le modalità del passaggio inverso:
1) resume()
2) interrupt() se è trascorso il tempo di sleep(tempo in millisecondi)
3) notify() o notifyAll() chiamati dal thread che possiede il monitor
4) quando finisce l’operazione di I/O bloccante
La vita del thread finisce nello stato Dead. Il passaggio dallo stato di Runnable o Not
Runnable in tale stato può avvenire per due motivi:
1) fine dell’esecuzione del codice contenuto nel metodo run()
2) stop() -se il thread stava eseguendo istruzioni “delicate” la chia-
mata di tale metodo potrebbe lasciare il sistema in uno stato
inconsistente.
Chat HELP DESK su HTTP
22
I thread nello stato Dead non devono essere considerati come thread persi, in quanto
nonostante vengano rilasciate da loro stessi gran parte delle risorse a loro attribuite,
mantengono ancora una loro traccia. Questa circostanza si rivela di notevole importan-
za, quando necessita sapere se un thread abbia terminato o no la sua esecuzione. Per
verificare questa circostanza esiste il metodo isAlive(), che restituisce true se il
thread si trova ancora nello stato Runnable o Not Runnable, mentre restituisce false
nel caso in cui il thread è nello stato Dead.
2.4.2 ADOZIONE DEL MULTITHREAD Nella mia applicazione la scelta del multithread è stata forzata poiché un’applicazione come
la mia deve svolgere molte funzioni concorrenti. Ecco una delle tante motivazioni: sarebbe
inammissibile che tutti gli utenti collegati al Server, tra cui gli utenti A e B, debbano
attendere per ore la fine del trasferimento di un file di grosse dimensioni dall’utente A
all’utente B senza poter né inviare né ricevere messaggi!
In Java ci sono due modi di creare un thread: estendere la classe Thread oppure
implementare l’interfaccia Runnable. La prima soluzione è la migliore ed è quella che è
stata applicata per creare tutti i thread della mia applicazione sia dal lato Client sia dal lato
Server. Tuttavia Java non supporta l’ereditarietà multipla e quando la classe che contiene il
metodo run() sta già ereditando da un’altra classe allora, per dedicarle un thread, l’unico
modo è implementare l’interfaccia Runnable. Questa operazione è sempre possibile
poiché Java permette di implementare più interfacce nella stessa classe. Mentre estendere
una classe significa ereditare tutto ciò che la classe ereditata possiede aggiungendo quindi
altri metodi e dati, implementare un’interfaccia invece, significa realizzare il contenuto dei
metodi che sono stati solamente dichiarati nell’interfaccia.
2.4.3 SINCRONIZZAZIONE Quando due o più thread condividono dati(files o variabili) e/o metodi che possono essere da
loro riferiti in maniera indesiderata, allora è necessaria una sincronizzazione. Più
precisamente la parte di codice che deve essere sincronizzata è detta sezione critica e può
essere solo una parte o l’intero body thread.
La cosa più importante è dunque dichiarare le sezioni critiche mediante la parola chiave
synchronized. In questo modo, quando inizia l’esecuzione di codice appartenente ad
una sezione critica il Java Runtime System mette un lock a tutti gli oggetti del thread che
Chat HELP DESK su HTTP
23
vengono riferiti nella sezione critica e impedendo che essi siano riferiti in modo indesiderato
da altri thread. Ogni volta che un thread accede ad una sezione critica di un oggetto, preleva
il monitor per quell’oggetto e questo impedisce agli altri thread di accedere alle sezioni
critiche di quell’oggetto poiché il monitor è unico. Quando un thread ha acquisito il monitor
per un oggetto, gli altri thread possono solamente accedere ai metodi non synchronized
dell’oggetto. Il rilascio del monitor e dei lock avviene quando il thread che li ha acquisiti
esce dalla sezione critica: adesso tutte le sezioni critiche dell’oggetto potranno essere
accessibili da altri thread che erano in attesa.
La seconda cosa da fare è coordinare le azioni tra i vari thread alternando, secondo le
esigenze, a seconda dei casi, l’accesso ai dati e alle variabili condivise tra i vari thread
concorrenti. Ciò può essere fatto grazie alle funzioni di libreria predefinite wait(),
notify() e notifyAll(). Il metodo wait() pone il thread nello stato Not Runnable
finché un altro thread, quello che ha il monitor, invoca il metodo notify() o
notifyAll(). L’uso di queste tre funzioni potrebbe sembrare apparentemente inutile non
è così. In un sistema operativo che utilizza uno Scheduler non basato su time-sliced la loro
assenza porterebbe, prima o poi, inevitabilmente al deadlock e quindi a un blocco
irreversibile dell’applicazione o parte di essa.
22..55 GGEESSTTIIOONNEE DDEELLLLEE EECCCCEEZZIIOONNII La gestione delle eccezioni è il meccanismo fornito da Java per il trattamento di una qualun-
que situazione “imprevista”' o “anomala” durante l'esecuzione di un programma ed è perfet-
tamente integrato con la metodologia orientata ad oggetti. L'idea di base è che quando si veri-
fica un imprevisto, il metodo attivo in quel momento non completa l'esecuzione, ma “getta” o
“lancia” (throw) un'eccezione che viene passata al metodo chiamante. Il comportamento
default di un metodo che riceve un'eccezione è di passare a sua volta l'eccezione al metodo
chiamante, terminando immediatamente l'esecuzione. Quando risalendo la catena delle chia-
mate di metodi l'eccezione raggiunge il metodo main, l'esecuzione del programma termina
stampando un opportuno messaggio di errore.
La potenza del meccanismo di gestione delle eccezioni di Java sta nel fatto che un'eccezione
gettata da un metodo può essere catturata (catch) dal metodo chiamante, e trattata con op-
portune istruzioni senza causare necessariamente la terminazione dell’intero programma.
Java ha una ricca gerarchia di eccezioni predefinite, ma ogni applicazione, come nel caso
della mia, per esempio la RaidayException, può definirne di nuove per meglio caratte-
Chat HELP DESK su HTTP
24
rizzare le situazioni anomale che si possono verificare. Quando ci si aspetta che un pezzo di
codice possa generare un'eccezione, lo si può racchiudere in un blocco speciale, detto blocco
try. Dopo questo blocco ci devono essere uno o più blocchi catch che contengono le i-
struzioni da eseguire nel caso l'eccezione venga effettivamente lanciata.
Il blocco try può essere seguito da un numero arbitrario di blocchi catch. Se c'è almeno
un blocco catch, allora il blocco finally è facoltativo. Nello schema, per
<istruzioni-XXX>; intendiamo una sequenza di istruzioni Java separate da “;”.
La forma generale del costrutto utilizzato è la seguente:
try {
<istruzioni-try>;
}
catch (<classe-eccezione1> <id1>){
<istruzioni-catch1>;
}
...
catch (<classe-eccezioneN> <idN>){
<istruzioni-catchN>;
}
finally {
<istruzioni-finally>;
}
Il comportamento del costrutto try-catch-finally può essere descritto,
informalmente, nel seguente modo. Si comincia l'esecuzione delle <istruzioni-try>.
Se l'esecuzione termina senza fallimenti, allora si eseguono le eventuali <istruzioni-
finally> e si termina. Altrimenti, se una delle istruzioni in <istruzioni-try> genera
un'eccezione ecc, si cerca il primo blocco catch tale che ecc sia istanza della
corrispondente <classe-eccezioneX>. Se un tale blocco esiste, se ne eseguono le
<istruzioni-catchX> corrispondenti dopo aver associato ecc all'identificatore
<idX>; infine si eseguono le eventuali <istruzioni-finally>. In questo caso
l'eccezione è stata catturata con successo. Se invece ecc non è istanza di nessuna delle classi
di eccezioni dei blocchi catch, allora vengono comunque eseguite le eventuali
<istruzioni-finally>, e l'eccezione ecc viene passata al chiamante.
Chat HELP DESK su HTTP
25
Infine Java consente di generare e lanciare eccezioni in un qualunque punto di un program-
ma, purché queste siano controllate in uno dei modi descritti sopra.
22..66 UUTTIILLIIZZZZOO DDII UUNN DDAATTAABBAASSEE L’utilizzo di un database nell’applicazione Server è stato deciso soprattutto per scopi didatti-
ci. Infatti, per velocizzare l’applicazione Server, il contenuto del database su disco viene ca-
ricato in memoria RAM e gestito dalla classe OnlineDB. Solo alcune operazioni vengono
eseguite anche sul file residente su disco rigido per mantenere la consistenza dei dati in caso
di un problema al Server, ma ciò verrà discusso dettagliatamente in seguito. I dati contenuti
nel database su disco accounts.mdb sono quelli di una semplice tabella, denominata Utenti,
con due sole colonne contenenti gli username(vincolo di primary key) e le password degli
utenti che si sono registrati.
username password
Antonello Sd7734
Marta boooo
prova prova
… …
… …
… …
Infatti, essendo il vincolo di primary key sulla colonna username implementato anche a livel-
lo applicazione, delle informazioni in un formato così semplice potevano essere tranquilla-
mente memorizzate in un file di testo. Tuttavia non tutto il male viene per nuocere. Infatti un
sistema di gestione di basi di dati (Data Base Management System o DBMS) è un sistema
software in grado di gestire collezioni di dati che siano grandi, condivise e persistenti, assicu-
rando la loro affidabilità e privatezza.
Un DBMS può essere visto come uno strato di comunicazione tra applicazione e dati che
permette lo scambio di informazioni tra questi attraverso un linguaggio di interrogazione, in
questo caso SQL.
Il JDBC è un insieme di classi e interfacce finalizzate ad interagire con i server di database
locali e remoti che supporta l’esecuzione di query SQL e l’analisi dei risultati delle stesse.
ODBC è un’interfaccia di comunicazione con DBMS, indipendente da piattaforma e
database, ma è realizzata in linguaggio C e quindi non è direttamente utilizzabile con Java.
Chat HELP DESK su HTTP
26
JDBC adatta ODBC alle particolari caratteristiche del linguaggio Java consentendo l’utilizzo
dei moltissimi driver già sviluppati da ODBC.
Una base di dati può essere impostata secondo diversi tipi di modelli (logici) di rappresenta-
zione. Quello più comune, che è anche il più semplice dal punto di vista umano, è il modello
relazionale. In questo modello, i dati sono raccolti all'interno di relazioni. Ogni relazione è
una raccolta di nessuna o più tuple di tipo omogeneo. La tupla rappresenta una singola in-
formazione completa, in rapporto alla relazione a cui appartiene, e questa informazione è
suddivisa in attributi. Una relazione, nella sua definizione, non ha una “forma” particolare,
tuttavia questo concetto si presta a una rappresentazione tabellare: gli attributi sono rappre-
sentati dalle colonne e le tuple dalle righe. Preferisco non dilungarmi oltre sul modello rela-
zionale poiché una tabella così semplice senza alcun vincolo o collegamento si commenta da
sola.
Per quanto riguarda SQL sono state utilizzate solo alcune delle operazioni fondamentali SE-
LECT, INSERT e DELETE.
La forma più semplice di esprimere la sintassi necessaria a interrogare una sola tabella è
quella espressa dallo schema seguente:
SELECT espress_col_1[,...espress_col_N]
FROM tabella
[WHERE condizione]
L'inserimento di una nuova riga all'interno di una tabella viene eseguito attraverso l'istruzio-
ne INSERT. Dal momento che nel modello di SQL le colonne sono ordinate, è sufficiente in-
dicare ordinatamente l'elenco dei valori della riga da inserire, come mostra la sintassi seguen-
te:
Chat HELP DESK su HTTP
27
INSERT INTO nome_tabella
VALUES (espressione_1[,...espressione_N])
La cancellazione di righe da una tabella è un'operazione molto semplice e viene eseguito at-
traverso l'istruzione DELETE. È richiesta solo l'indicazione del nome della tabella e la condi-
zione in base alla quale le righe devono essere cancellate.
DELETE FROM tabella
[WHERE condizione]
Se la condizione non viene indicata, si cancellano tutte le righe.
Per quanto riguarda l’incapsulamento dei dati, data la semplicità della base di dati, è stato
sufficiente utilizzare un modello a due strati.
Prima di ottenere la connessione al database, è necessario ricordarsi di importare il package
java.sql in modo da poter utilizzare le classi e le interfacce di JDBC. Per questo, nelle li-
nee di codice del programma dedicate all’importazione dei package, andrà specificato:
import java.sql.*;
Ottenere una connessione al database tramite JDBC è abbastanza semplice ed indipendente
da quale tipo di DBMS si stia utilizzando. E’ necessario solamente indicare all’applicazione,
tramite il DriverManager, quale driver utilizzare e farsi rilasciare un oggetto
Connection che servirà per dialogare con la base dati. E’ da notare che per identificare il
database è necessario specificare l’URL, ossia l’indirizzo verso il quale tentare la connessio-
ne. Questa stringa può variare in base al tipo di driver utilizzato, e, alcune volte, può richie-
dere anche la specificazione di username e password dell’utente. Le linee di codice che rea-
lizzano queste procedure iniziali per un database ODBC sono le seguenti:
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
String url = "jdbc:odbc:NomeDatabase";
Connection con = DriverManager.getConnection(url, "Username", "Pass-
word");
Ovviamente, la ricerca di un driver e il tentativo di connessione potrebbero non andare a
buon fine e generare, di conseguenza, un’eccezione. Per questo, è necessario inserire le istru-
Chat HELP DESK su HTTP
28
zioni appena viste, in un try-catch. Per la manipolazione dei dati, sono stati utilizzati so-
lamente altri due oggetti del package: Statement e ResultSet. Il primo oggetto permet-
te di effettuare qualsiasi operazione SQL sul database come SELECT, INSERT e DELETE
ecc. Il secondo oggetto permette invece, di manipolare i risultati ottenuti attraverso una
query, effettuata con uno Statement. L'oggetto Statement "semplice" viene creato dal
metodo createStatement() invocato sull’oggetto Connection. Utilizzeremo Statement
per creare una query SQL la cui esecuzione è richiesta una sola volta durante l'esecuzione
dell'applicazione java. In questo caso la query viene preparata e inviata al DBMS. Quest'ul-
timo la analizza sintatticamente, la ottimizza, la compila e la esegue. Inviati i risultati all'ap-
plicazione che aveva inoltrato la richiesta, la query viene rilasciata (o, per rendere meglio l'i-
dea, "dimenticata") dal DBMS che l'ha eseguita. Il metodo executeQuery() di Statement
prepara ed invia la query in un singolo passo. I costrutti try - catch permettono di gesti-
re gli errori che possono verificarsi durante l'esecuzione del programma. Il risultato della
query viene fornito attraverso l'oggetto ResultSet che è consultabile "per righe" tramite
un "cursore" (una specie di segnalino). Ogni riga è composta da un numero di campi variabi-
le a seconda di quanti ne abbiamo richiesti con la query. Nel mio caso i campi sono: userna-
me e password. E' possibile accedere al k-esimo campo di una determinata riga tramite la
funzione getString(k). Per passare alla riga successiva (spostare il cursore alla riga suc-
cessiva) è possibile utilizzare la funzione next(), tuttavia non è possibile tornare indietro.
Il metodo next() restituisce il valore null quando il cursore è già posizionato sull'ultima
riga.
22..77 IINNTTEERRFFAACCCCIIAA GGRRAAFFIICCAA L’interfaccia grafica a finestre di questa applicazione è inizialmente progettata utilizzando
l’applicazione Sun Studio 1 e poi è stata rifinita operando le modifiche direttamente sul codi-
ce Java. Tuttavia, l’applicazione stampa dei messaggi di commento tramite la
System.out.print(), utili per il debug, utilizzando una normale interfaccia testuale.
L'interfaccia grafica di un programma è composta dai cosiddetti componenti GUI (Graphics
User Interface), essi sono dei componenti che servono per l'input o per l'output, ed hanno un
aspetto grafico. Sono ad esempio dei componenti GUI di un programma tutti i menù, i botto-
ni, le label, eccetera…di questo.
In Java i componenti GUI sono predefiniti nei packages: javax.swing e java.awt.
Swing è stato interamente scritto in Java, usando il package awt, e mette a disposizione del-
Chat HELP DESK su HTTP
29
l'utente tante classi presenti anche in awt, ma notevolmente migliorate e potenziate, mette i-
noltre tante altre classi non presenti in awt.
Per creare delle finestre basta estendere
una qualunque classe secondo la classe
javax.swing.JFrame oppure come
JDialog e poi istanziare un oggetto di
tale classe. Fatto ciò la classe si tramuta
una vera e propria finestra di Windows,
un Frame su cui è possibile eseguire una
serie d’operazioni e a cui è possibile
aggiungere dei GUI. Sulle Dialog apro una piccola parentesi: sono dei Frame senza ico-
na, riducibili a icona e massimizzabili, sono molto utili per fare appunto dei dialoghi veloci
con l'utente. Dopo aver deciso l’aspetto della finestra allora viene invocato il metodo set-
Location() che dichiara, secondo le coordinate x e y, la posizione dell'angolo destro in
alto della finestra sul desktop. Poi si chiama il metodo setSize(), che permette di specifi-
care larghezza e altezza della finestra, e infine questa può essere resa visibile invocando il
metodo show().
Nel mio caso ho deciso, per comodità, di rendere le finestre non ridimensionabili, ma aventi
tutte una grandezza massima di 640x480 pixel, la minima risoluzione standard.
Per l’utilizzo dei vari componenti GUI si rimanda ad una guida specifica e dettagliata.
Per costruire una interfaccia grafica che si rispetti bisogna non solo combinare i componenti
GUI ma è anche ascoltarne gli eventi per rendere possibile l’interazione con l’utente. Gli e-
venti, predefiniti nel package java.awt.event, di tipo ActionEvent rappresentano
un'azione compiuta sulle GUI da parte dell'utente, per esempio premere un bottone. In parti-
colare MouseListener ascolta gli eventi provenienti dal mouse, KeyListener ascol-
ta eventi provenienti dalla tastiera, ecc.
Dopo aver implementato l'interfaccia ActionListener bisogna ridefinirne l’evento
actionPerformed (ActionEvent e), che viene invocato quando viene eseguita una
azione sul componente GUI (o sui componenti) a cui è associato. Infine per associare al GUI
l'ascoltatore d’eventi che ho definito ho usato il metodo addActionListener
(ActionListener ascoltatore) del GUI.
Chat HELP DESK su HTTP
30
22..88 VVIISSUUAALLIIZZZZAATTOORREE DDII IIMMMMAAGGIINNII Nel linguaggio Java è possibile disegnare su un’Applet semplicemente ridefinendone il
metodo paint, questo metodo viene automaticamente invocato dal sistema quando la
finestra contenente l'applet va in primo piano, quindi ogni comando grafico all’applet sarà
dato nel metodo paint dell’applet quando l’applet ha disegnato, e si vogliono visualizzare
eventuali modifiche è possibile invocare il metodo repaint() oppure il metodo
update(Graphics g) che cancella l'area in cui l’applet ha disegnato e ne reinvoca la
paint. Graphics è una classe che non può essere istanziata, ma nella paint viene ricevuta
come parametro. La classe Graphics è stata potenziata aggiungendo la classe
Graphics2D, che la estende aggiungendo notevoli potenzialità alla grafica in Java. Il
metodo paint(Graphics g) non può essere invocato direttamente.
Non solo l’applet ha il metodo paint, che può essere ridefinito, ma anche gli oggetti di tipo
Component, ovvero tutti i GUI, quindi per cambiare l'aspetto grafico di un qualsiasi com-
ponente grafico basta ridefinirne il metodo paint. Infatti nel mio caso ho utilizzato come
lavagna un JPanel su cui le immagini, salvate con formato gif o jpg, vengono visualizzate
tramite il Graphics2D e vengono tenute aggiornate grazie al metodo richiamato automati-
camente paintComponent(Graphics g).
Nella classe Graphics ci sono vari metodi drawImage che richiedono i due parametri I-
mage e ImageObserver. Image rappresenta l'immagine da visualizzare, essa è una clas-
se astratta che fornisce un accesso indipendente dal formato a immagini grafiche, oggetti di
questa classe vengono creati usando metodi di altre classi che creano delle immagini, a se-
conda del contesto in cui si vogliono usare le immagini. ImageObserver, e rappresenta in
pratica l'oggetto grafico su cui verrà visualizzata l'immagine.
Component implementa l'interfaccia ImageObserver, di conseguenza la implementano
tutte le sue estensioni, tra cui:
• Tutti i GUI
• Le Applets
• Tutte le finestre (tra cui i Frames e i JDialog)
La classe Toolkit ha sia createImage() che getImage().
La nuova classe Graphics2D mette a disposizione altri metodi drawImage, tra cui alcuni
che hanno un parametro di tipo AffineTransform che come si capisce dal nome è una
trasformazione affine dell'immagine, ovvero un ridimensionamento, una rotazione o una tra-
Chat HELP DESK su HTTP
31
slazione, o una combinazione di queste. Ciò permette una visualizzazione ottimale
dell’immagine caricata da disco sulla lavagna, anche se le loro dimensioni non combaciano.
Come detto nel paragrafo precedente è possibile aggiungere al visualizzatore di immagini dei
MouseListener che permettono di tracciare col mouse sulla lavagna, che eventualmente
ha delle immagini come sfondo, delle linee.
La cosa più semplice da disegnare è la linea, per farlo usiamo il metodo drawLine() di Gra-
phics:
drawLine(Iniziox, Inizioy, Finex, Finey)
il quale disegna una linea che parte dal punto (Iniziox, Inizioy) e arriva al punto (Finex,
Finey). Prima di usare la drawLine()si possono cambiare i colori delle cose disegnate.
I colori si cambiano usando il metodo setColor(Color c) della classe Graphics.
Color è un'altra classe di awt che permette di definire un colore tramite il costruttore:
Color(float r, float g, float b)
il quale crea un colore specificando i valori RGB (Red - Green - Blue, ovvero Rosso - Verde
- Blu) con dei valori compresi tra 0 e 255.
22..99 II SSUUOONNII Vorrei sottolineare che l'argomento che sto per trattare non è valido per le vecchie versioni di
Java, cioè si possono creare delle applet che leggono e riproducono file di tipo .au o .wav,
usando i metodi play di Applet e l'interfaccia AudioClip, solo a partire dalla versione 1.3
di Java2.
Innanzitutto dobbiamo importare il package Applet e poi reperire il file contenente il suo-
no, e questo lo facciamo come al solito istanziando un oggetto della classe File (di
java.io). A questo punto istanziamo un oggetto di tipo audio clip dopo aver prelevato
l’URL dal file:
AudioClip audioClip = Applet.newAudioClip(completeURL);
Chat HELP DESK su HTTP
32
Ora per utilizzare il sistema audio basta invocare sull’oggetto appena istanziato i metodi
play() e stop(), predefiniti nell’interfaccia audioclip.
Utilizzando un’ architettura multithread è possibile mandare in esecuzione più suoni contem-
poraneamente, tutto mentre l’applicazione sta girando.
22..1100 SSEELLEETTTTOORREE DDII FFIILLEESS EE IINNDDIICCAATTOORRII DDII AAVVAANNZZAAMMEENNTTOO Il package predefinito javax.swing contiene alcune classi che implementano le funziona-
lità del GUI, di grande effetto e utilità. Queste rendono possibile la selezione di un file resi-
dente su hard disk e la visualizzazione di un indicatore di avanzamento che rende consapevo-
le l’utente del reale stato di progresso di un’operazione molto lunga, per esempio la trasmis-
sione di un file di grosse dimensioni.
La classe predefinita javax.swing.filechooser implementa una completa interfaccia
grafica che consente di esplorare il disco rigido locale alla ricerca di un file. Una volta che il
file è stato selezionato viene restituito un oggetto di tipo File. Oltre ai metodi predefiniti, è
possibile estendere le funzionalità della classe personalizzando alcuni suoi componenti. Per
esempio è possibile introdurre un filtro di visualizzazione personalizzato, che nel mio caso
rende visibili solo i file di tipo immagine supportati(.gif, .jpeg, .tiff), oppure un visualizzatore
automatico di anteprime delle immagini contenute nei files.
La classe ProgressMonitor implementa una completa interfaccia grafica che consente di
visualizzare una finestra di dialogo, con titolo selezionabile, che mostra in modo dettagliato
l’avanzamento di un task molto lungo. La barra si basa sul valore finale che l’indicatore deve
raggiungere e ogni 100 millisecondi il valore corrente viene aggiornato grazie al metodo
setProgress(int). Ciò rende perfettamente l’idea dello stato di trasmissione di un file,
anzi indica in modo precisissimo la quantità di bytes che è stata inviata o ricevuta. La finestra
ha inoltre un pulsante che permette di annullare l’operazione di cui la il
ProgressMonitor sta tracciando lo stato di avanzamento.
Chat HELP DESK su HTTP
33
33 IILL DDIIAALLOOGGOO TTRRAA CCLLIIEENNTT EE SSEERRVVEERR
33..11 SSCCAAMMBBIIOO DDII DDAATTII AATTTTRRAAVVEERRSSOO LLAA RREETTEE Prima di procedere con una descrizione dettagliata del funzionamento delle applicazioni
Client e Server è opportuno chiarire come avviene lo scambio d’informazioni tra esse
attraverso la rete.
I dati che sono inviati dal Client verso il Server viaggiano secondo questo schema:
I dati che sono inviati dal Server verso il Client(IP Pubblico) viaggiano secondo questo
schema:
I dati che sono inviati dal Server verso il Client(IP Privato) viaggiano secondo questo
schema:
Chat HELP DESK su HTTP
35
Il package net ha la funzione di mascherare e rendere trasparente alla classe
XxxxxxConnectionCenter il tipo di connessione che si sta effettivamente utilizzando
per il collegamento sulla rete, tra Client e Server e viceversa. La classe ProxyInfo, a
seconda del ProxyType ricevuto, istanzia la connessione verso l’altra sponda della rete
utilizzando una tra le classi del package net: DirectConnection, HttpConnection
e SocksConnection. Queste tre sono implementazioni della classe interfaccia
Connection. Per garantire la trasparenza a livello superiore l’interfaccia Connection
prevede l’overriding di tutte le funzioni più importanti di una Socket: avaiable, read, write,
flush, getInputStream, getOutputStream, getInBufferedReader e getSocket. In particolare
questa funzione ritorna proprio la Socket. Insomma la classe
XxxxxxConnectionCenter, una volta per tutte impostato il ProxyInfo, non ha più
bisogno di sapere se ci si sta connettendo al Client/Server tramite un ProxyServer oppure in
modo diretto: tutto ciò che deve fare è utilizzare una Connection.
Sostanzialmente la classe XxxxxxConnectionCenter è il centro di controllo di tutte le
connessioni uscenti sia dal Client che dal Server e contiene delle funzioni di tipo
CreaXXXConnection, GetXXXConnection e ChiudiXXXConnection. Grazie ad
esse è infatti possibile rispettivamente: creare una connessione e agganciarla direttamente al
thread voluto all’interno del Client/Server, ottenere il Socket della connessione creata,
chiudere tale connessione.
Dall’altro lato della rete c’è in ascolto sulla porta 80 un thread ad altissima priorità: il
XxxxxxConnectionHandler. Questa funzione aggancia tutte le connessioni entranti e
passa i Socket al thread XxxxxxConnectionDeliver.
Nella modalità ad IP Privato, dal lato Client, il thread ClientConnectionHandler
non viene mandato in esecuzione. Ciò è compensato dal fatto che, quando il Server ne fa
richiesta(grazie alla stabile MainConnection), una connessione riferita ad un Socket vergine
viene passata direttamente al ClientConnectionDeliver(dal
MainConnectionListenerThread) dal quale questo thread inizia a leggere e scrivere dati.
Questa distinzione è facilmente mascherata da un if posizionato in tutte le funzioni
CreaXXXConnection del ServerConnectionCenter. Detto ciò si rende evidente
che, una volta settati i parametri di connessione iniziali, le classi
XxxxxxConnectionCenter e le loro funzioni mascherano totalmente l’esistenza o
meno di un ProxyServer interposto tra Client e Server e la modalità di connessione ad IP
Pubblico o Privato. Questo è un grande esempio della potenza del linguaggio Java in quanto
Chat HELP DESK su HTTP
36
a modularizzazione e incapsulamento: è possibile risolvere un grande problema
spezzettandolo in tanti problemi più piccoli risolvibili singolarmente.
33..22 IILL CCOODDIICCEE CCHHEE IIDDEENNTTIIFFIICCAA IILL TTIIPPOO DDEEII MMEESSSSAAGGGGII Per convenzione scelgo che in tabella tutti i valori selezionati sono inviati da destra verso si-
nistra e tutti gli altri da sinistra verso destra
Una volta istaurato il canale di comunicazione tra le classi ClientConnectionCenter
e ServerConnectionDeliver c’è un protocollo di handshaking, appositamente creato
da me, che permette di passare il Socket ricevuto a uno specifico thread deciso in base ai dati
che arrivano sul canale. Vediamo uno schema: Funzione Chiamata sul
ClientConnectionCenter
Messaggi di handshaking
scambiati
Thread invocato, funzione chiamata
o operazione eseguita
creaMainConnection 0 %autorizzato% manageMainConnection()
creaDatabaseConnection 1 %autorizzato% databaseThread
creaSTMConnection 2 %autorizzato% singleTalkManagerThread
creaMTMConnection 3 %autorizzato% multiTalkManagerThread
creaManagementConnection 4 %autorizzato% managementConnection()
creaSlideManagerConnection 5 %autorizzato% slideManagerThread
creaFileManagerConnection 6 %autorizzato% fileManagerThread
creaServerRequestedSocketConnection 7 %autorizzato%
Aggiunta di una connessione vergine
nel vettore ONDBReadyConnection
pronta all’uso
altro
codice Errore e fine procedura
Ciò vale anche nella direzione opposta poiché è possibile creare un canale di comunicazione
tra le classi ServerConnectionCenter e ClientConnectionDeliver:
Funzione Chiamata sul
ServerConnectionCenter
Messaggi di handshaking
scambiati
Thread invocato, funzione chiamata o
operazione eseguita
creaClientHandlerConnection +0 %autorizzato% messageProcessorThread
creaClientSlideReciverConnection 1 %autorizzato% slideProcessorThread
creaClientFileReciverConnection 2 %autorizzato% fileProcessorThread
creaClientHandlerConnection + 3 %autorizzato% Chisura connessione
altro codice Errore e fine procedura
Ovviamente una qualunque classe che invochi sull’ XxxxxxConnectionCenter una
funzione di tipo GetXXXConnection può ottenere il Socket del collegamento: ciò permet-
Chat HELP DESK su HTTP
37
te di mettere in comunicazione diretta qualunque thread del Client con qualunque thread del
Server e viceversa utilizzando come unica porta di ascolto la porta la porta 80 del server!
Tuttavia dopo aver messo in collegamento i due thread desiderati è bene chiarire la sequenza
di comandi che il thread servente accetta come validi.
Dopo la chiamata della funzione manageMainConnection le seguenti sequenze di codice in-
viate sulla connessione stabilita verso il Server causano l’operazione riportata nella colonna
più a destra: Thread Chiamante Messaggi di handshaking scambiati Operazione
ClientConnectionCenter username password /*stop*/ Chiusura
mainconnetion
ClientConnectionCenter username password Client
IP
Client
Port
Proxy
Type
Proxy
IP
Proxy
Port
Istaurazione
mainConnection
Dopo l’accesso al thread databaseThread le seguenti sequenze di codice inviate sulla con-
nessione stabilita verso il Server causano l’esecuzione dell’operazione riportata nella colonna
più a destra: Thread Chiamante Messaggi di handshaking scambiati Operazione
ClientConnectionCenter reg Registrazione nuo-
vo utente
ClientConnectionCenter dereg Deregistrazione
utente esistente
ClientConnectionCenter Altro codice Eccezione
Dopo l’accesso al thread singleTalkManagerThread le seguenti sequenze di codice inviate sulla
connessione stabilita verso il Server causano l’esecuzione dell’operazione riportata nella co-
lonna più a destra: Thread Chiamante Messaggi di handshaking scambiati Operazione
ClientConnectionCenter mittente destinatario messaggio Ricezione messag-
gio per inoltro
Dopo l’accesso al thread multiTalkManagerThread le seguenti sequenze di codice inviate con-
nessione stabilita verso il Server causano l’esecuzione dell’operazione riportata nella colonna
più a destra: Thread Chiamante Messaggi di handshaking scambiati Operazione
ClientConnectionCenter SendM mittente destinatario messaggio Ricezione messag-
gio per inoltro
ClientConnectionCenter lStanze
Invio al Client della
lista delle stanze
aperte
ClientConnectionCenter mTalk Ok Aggiunta di un
Chat HELP DESK su HTTP
38
nuovo utente in una
stanza
ClientConnectionCenter mTalk Altri codici
Errore
nell’aggiunta di un
nuovo utente in una
stanza
ClientConnectionCenter exit Lista netfriend aggiornata a
tutti i membri della stanza
Uscita di un utente
da una stanza
ClientConnectionCenter priv Esito esistenza destinatarioConversazione pri-
vata
Dopo la chiamata della funzione managementConnection le seguenti sequenze di codice in-
viate sulla connessione stabilita verso il Server causano l’esecuzione dell’operazione riporta-
ta nella colonna più a destra: Thread Chiamante Messaggi di handshaking scambiati Operazione
ClientConnectionCenter username password 10 Nessuna operazione
ClientConnectionCenter username password 11 Invio al Client della lista de-
gli utenti connessi
ClientConnectionCenter username password 12 okConferma che l’utente che si
vuole contattare è online
ClientConnectionCenter username password 12 koNotifica che l’utente che si
vuole contattare è offine
ClientConnectionCenter username password esito Disconnessione dal Server
ClientConnectionCenter username password Altro codice Nessuna operazione o
Dopo l’accesso al thread slideManagerThread le seguenti sequenze di codice inviate sulla con-
nessione stabilita verso il Server causano l’esecuzione dell’operazione riportata nella colonna
più a destra: Thread Chiamante Messaggi di handshaking scambiati Operazione
ClientConnectionCenter mittente destinatario Nome file dimensione Ricezione di una
slide per inoltro
Dopo l’accesso al thread fileManagerThread le seguenti sequenze di codice inviate sulla con-
nessione stabilita verso il Server causano l’esecuzione dell’operazione riportata nella colonna
più a destra: Thread Chiamante Messaggi di handshaking scambiati Operazione
ClientConnectionCenter mittente destinatario Nome file dimensione Ricezione di un file
per inoltro
Dopo la chiamata della funzione messageProcessorThread le seguenti sequenze di codice
inviate sulla connessione stabilita verso il Client causano l’esecuzione dell’operazione ripor-
tata nella colonna più a destra:
Chat HELP DESK su HTTP
39
Thread Chiamante Messaggi di handshaking scambiati Operazione
ServerConnectionCenter mittente messaggio /*ko*/
Notifica che il desti-
natario da contattare è
offline
ServerConnectionCenter mittente messaggio Altro codice
Visualizzazione del
messaggio(testo o
grafica) ed eventuale
apertura della finestra
di nuova conversa-
zione privata
Dopo la chiamata della funzione slideProcessorThread le seguenti sequenze di codice inviate
sulla connessione stabilita verso il Client causano l’esecuzione dell’operazione riportata nella
colonna più a destra: Thread Chiamante Messaggi di handshaking scambiati Operazione
ServerConnectionCenter mittente Nome file dimensione Ricezione di una
Slide
Dopo la chiamata della funzione fileProcessorThread le seguenti sequenze di codice inviate
sulla connessione stabilita verso il Client causano l’esecuzione dell’operazione riportata nella
colonna più a destra: Thread Chiamante Messaggi di handshaking scambiati Operazione
ServerConnectionCenter mittente Nome file dimensione Ricezione di un file
Dopo l’instaurazione della mainConnection Client e Server scambiano su di essa alcuni mes-
saggi di ping e di altro tipo nella modalità ad IP Privato. Le seguenti sequenze di codice lan-
ciate dal Server verso il Client causano l’esecuzione dell’operazione riportata nella colonna
più a destra: Thread Chiamante Messaggi di handshaking scambiati Operazione
Ping ping ping Richiesta di ping
ServerConnectionCenter ServerRequestConnection
Richiesta al Client di
inoltrare una nuova
connessione vergine
verso il server
Per concludere questa sessione vorrei render noto che lo scambio di messaggi tra Client e
Server, per portare a termine alcune delle operazioni sopra elencate, va molto oltre quello ri-
portato nelle tabelle. Anzi, in alcuni casi, è necessario creare nuovi Socket, aprire delle con-
nessioni di tipo loop-back(dal Server al Server oppure dal Client al Client) e chiamare in
causa altri thread. Ci sono due motivi dietro questa scelta di sintesi: semplificare lo schema al
Chat HELP DESK su HTTP
40
minimo indispensabile per comprendere rapidamente le parti fondamentali, l’albero dei
cammini sulle possibili combinazioni d’eventi che si potrebbero verificare si espande in mo-
do esponenziale scendendo di livello. Ciò non vuol dire che la complessità del codice è espo-
nenziale ma solo che il numero delle scelte lo è. In realtà, senza passare per cicli, iterazioni e
ricorsioni viene sempre scelto rapidamente uno e un solo cammino da seguire durante il dia-
logo tra le parti.
Chat HELP DESK su HTTP
41
44 LL’’AAPPPPLLIICCAAZZIIOONNEE CCLLIIEENNTT
44..11 LLAA FFAASSEE DDII IINNIIZZIIAALLIIZZZZAAZZIIOONNEE La classe principale che deve essere mandata in esecuzione è RaidayClient. I valori
delle variabili di istanza di questa classe permettono di manipolare i parametri fondamentali
dell’applicazione, che si trasmettono a catena tra tutti i thread e le classi successivamente
istanziate. All’avvio viene eseguito un parsing degli argomenti passati dalla linea di
comando, poi viene istanziata una variabile statica del tipo:
ClientConnectionCenter. In essa vengono archiviate le informazioni: IP e Porta
d’ascolto del server, IP e Porta d’ascolto del ProxyServer, la porta su cui sta ascoltando il
Client. A questo punto viene inizializzata una variabile del tipo ProxyInfo. Questa classe,
una volta che è stata settata ad un valore(Connessione Diretta, Proxy HTTP, Proxy Socks 4 o
5) maschera alla classe ClientConnectionCenter il tipo di connessione realmente utilizzata
per trasmettere i dati. Tale procedimento è stato spiegato approfonditamente nella sezione
“Dialogo tra Client e Server”. Ritorniamo a ora alla classe RaidayClient. Dopo aver
istanziato gli oggetti che permettono di creare la connessione di default, viene chiamato il
costruttore della classe RaidayClient. Questo metodo inizia subito ad istanziare un oggetto
del tipo SoundManager. Questa classe avvia un thread dedicato alla gestione dei suoni del
programma. All’inizializzazione vengono caricate dal disco rigido in memoria RAM i 15
files audio che poi verranno richiesti durante la normale esecuzione. Uno dopo l’altro i files
vengono aggiunti ad un oggetto di tipo SoundList. Sfruttando la path relativa dell’URI
riferita al nome del file la classe SoundList chiama un nuovo thread di tipo SoundLoader
dedicato al caricamento in memoria di ogni singolo file audio. Mentre questi thread si
dedicano a creare in memoria la banca dati completa di tutto l’audio necessario per il Client,
la classe RaidayClient si dedica a inizializzare i componenti grafici(etichette, finestre,
bottoni, ecc.) e le finestre: MyJDialog, MyJFOpzioni, MyJFRegistrazione,
MyJFCUtente, ClientMainFrame, MyJFLogin. Tutte queste classi Java, tranne la
prima che estende JDialog, estendono la classe JFrame predefinita in Java ed hanno uno
scheletro di base molto simile. Il loro costruttore compie i seguenti passi: inizializza tutti i
vari componenti gui utilizzati(textfield, button, combobox, label, ecc.), viene impostato il
colore di sottosfondo, i vari gui vengono ridimensionati, posizionati e resi visibili, vengono
inizializzati e aggiunti i vari Listeners che rendono possibile l’interazione con l’utente, viene
impostato lo sfondo e infine viene aggiunto tutto al ContentPane della JFrame che la classe
Chat HELP DESK su HTTP
42
sta estendendo. Ritorniamo alla classe RaidayClient. A questo
punto viene resa visibile la finestra principale di Login, associata
alla classe Java MyJFLogin, e l’applicazione Client si mette in
attesa che l’utente compia un operazione.
44..22 RREEGGIISSTTRRAAZZIIOONNEE EE DDEERREEGGIISSTTRRAAZZIIOONNEE Dopo l’inizializzazione l’operazione richiesta dall’utente può essere
quella di “re/deregistrazione” in cui viene resa visibile la finestra
associata alla classe Java MyJFRegistrazione.
A seconda del pulsante premuto vengono
chiamate due funzioni molto simili della classe RaidayClient:
Registrazione o Deregistrazione. Durante queste funzioni viene
invocato sulla classe ClientConnetionCenter il metodo
istanziaProxyInfo, che come visto prima reinizializza le classi
sottostanti che mascherano il tipo di connessione, e poi il metodo
creaDatabaseConnection, che crea una connessione diretta con il
Server. Su questo canale prima vengono inviati i dati inseriti
dall’utente, poi viene letto l’esito della “re/deregistrazione”, che viene
comunicato all’utente con una JDialog accompagnata da segnale
sonoro. Infine il canale viene chiuso grazie alla chiudiDatabaseConnection.
44..33 GGEESSTTIIOONNEE DDEELLLLEE OOPPZZIIOONNII DDII CCOONNNNEESSSSIIOONNEE AALL SSEERRVVEERR Se l’operazione richiesta dall’utente nella finestra di Login è quella di “Opzione Connessio-
ne”, viene subito resa visibile la finestra associata alla classe
Java MyJFOpzioni.
Una volta premuto il tasto di conferma, in base alle opzioni
impostate dall’utente, vengono eseguite una serie di
operazioni, tra cui la chiamata della funzione
setAndNewConnectionType su ClientConnectionCenter.
L’esito finale è la rigenerazione di tutti gli oggetti necessari
per la connessione ma col tipo selezionato nella finestra
MyJFOpzioni dall’utente.
Chat HELP DESK su HTTP
43
44..44 LLAA FFAASSEE DDII LLOOGGIINN Il terzo tipo d’operazione effettuabile dall’omonima finestra è quella di “Login”. Grazie ad
essa si può finalmente accedere al menù principale, ma solo dopo che sia stata completata
l’esecuzione della funzione collegati di RaidayClient. In questo momento vengono aperti i
Socket verso il Server e soprattutto viene impostato il tipo di connessione: ad IP Pubblico o
ad IP Privato. In ogni caso vengono istanziati due oggetti, uno del tipo
ClientConnectionHandler e l’altro del tipo ClientSwitch che è una funzione
virtuale. Viene cioè creato un vettore contenente tutte le conversazioni, sia private che
multiutente, aperte verso tutti gli utenti. Su questo vettore vengono usati metodi di
sincronizzazione per consentire l’accesso condiviso ai vari thread. La classe
ClientConnectionHandler, invece, è un thread ad altissima priorità che ha l’unico compito di
accettare le connessioni entranti da parte del Server, di qualunque tipo esse siano, e di
passarle ad un altro thread: il ClientConnectionDeliver. Non appena il socket
ottenuto verso il Server viene passato a questo thread a priorità normale, il
ClientConnectionHandlerThread si rimette immediatamente in ascolto per accettare nuove
eventuali richieste di connessione. Il ClientConnectionDeliverThread inizia a leggere i dati
provenienti dal Socket. A seconda del dato ricevuto le connessioni possono essere smistate ai
thread MessageProcessor, SlideProcessor, FileProcessor oppure viene
semplicemente inviato un acknowledge e la connessione viene subito chiusa. L’esistenza
della strana funzione readline è motivata nella sezione “problemi e soluzioni”. Ritorniamo
alla classe RaidayClient. Se il tipo di connessione selezionata dall’utente è di tipo ad IP
Pubblico allora vengono eseguite ulteriori due operazioni. Prima viene avviata la funzione
testAndGetClientListenPort il cui compito è cercare una porta libera sul Client su cui
ascoltare le connessioni provenienti dal Server: viene provata prima la porta 80, poi la porta
21 e poi altre porte a caso fino a che non se ne trova una libera. Poi questa porta viene
comunicata al ClientConnectionHandlerThread che viene mandato in esecuzione come
thread vero e proprio e messo in ascolto su di essa. Dopo questa biforcazione in ogni caso
viene creata la cosiddetta MainConnection tra Client e Server. Questa connessione viene
aperta all’atto del Login sul Server da ogni Client e viene mantenuta aperta fino all’atto della
disconnessione. La sua funzione è quella di comunicare al Server lo stato del Client, e nel
caso di IP Privato serve come canale di ascolto per le richieste di connessione dirette dal
Server verso il Client. Tale connessione viene infatti affidata a un thread del tipo
MainConnectionListener. In entrambi i casi di IP Privato o IP Pubblico su questa
connessione viaggiano dei messaggi di Ping tra Client e Server richiesti da questo ultimo ad
Chat HELP DESK su HTTP
44
intervalli di tempo regolari. In più, se si è connessi al server in modalità IP Privato, questa
classe accetta le richieste di connessioni entranti da parte del Server. Poiché l’IP del Client è
Privato il Server è impossibilitato a raggiungere il Client su qualunque porta. Quando il
Server ha bisogno di aprire una nuova connessione verso il Client allora manda una richiesta
sulla mainConnection. Il thread in questione accoglie la richiesta e crea una connessione
vergine verso il Server. Il Socket ottenuto viene dunque passato al
clientConnectionDeliverThread simulando perfettamente con questo meccanismo la
“serverSocket.accept” svolta dal clientConnectionHandlerThread. Dopo ciò avviene il solito
dialogo tra Client e Server e lo smistamento della connessione procede normalmente come
prima spiegato. Dopo aver mandato in esecuzione il
MainConnectionListenerThread nel caso di IP Privato, per velocizzare la
connessione tra Client e Server il Client crea di default tre connessioni vergini subito
utilizzabili per essere passate al clientConnectionDeliverThread in caso di richiesta dal
Server. Ciò riduce il tempo di latenza tra Client e Server che altrimenti sarebbe quadruplicato
rispetto alla modalità ad IP Pubblico. Le tre connessioni vergini vengono riposte in appositi
vettori e, ogni volta che una di esse viene utilizzata, il Client provvede immediatamente a
rimpiazzarla creandone una nuova e rimettendola nel vettore. Dopo queste procedure si può
udire una voce, grazie al sistema soundManager precaricato, il quale avverte che il Client è
nello stato Online per il Server. Viene dunque reso visibile il ClientMainFrame: la
finestra contenete il menù di comando principale del Client.
Se una qualunque delle procedure sopra elencate non viene terminata con successo, grazie a
un sistema di acknowledges e timeouts, tra Client e Server, correlato da un sistema di gestio-
ne delle eccezioni Java, allora la procedura di collegamento viene interrotta. Viene mostrato
all’utente, invece che la ClientMainFrame, una finestra di dialogo che comunica all’utente
l’errore verificatosi. Vorrei far presente che ogni qual volta viene premuto il bottone “OK”
dalla finestra di dialogo viene mandata in esecuzione la funzione OkDialogProcedure. A se-
conda della risposta ricevuta dal Server è questa funzione che decide quali finestre rendere
visibili e quali invece devono scomparire oltre a gestire i suoni e distruggere i talk inutilizza-
ti.
44..55 IILL MMEENNUU PPRRIINNCCIIPPAALLEE Il menu principale ha quattro pulsanti: Cambia Utente, Contatta User, Lista Canali e Scolle-
gati.
Chat HELP DESK su HTTP
45
Quando l’utente preme il pulsante “Scollegati” del menù principale viene attivata la funzione
scollegati di RaidayClient contenente una serie di istruzioni
che portano alla definitiva chiusura dell’applicazione
Client. Prima viene creata una ManagementConnection
verso il Server per comunicare l’operazione di
scollegamento, poi viene attivato un segnale acustico e
viene visualizzata una finestra di dialogo che comunica
all’utente cosa sta accadendo. Nel frattempo, solo nel caso
di connessione ad IP Pubblico, viene aperta una
connessione loop-back verso porta su cui sta ascoltando il
Client stesso e, grazie alla funzione arrestaClientConnec-
tionHandler, viene inviato un particolare codice che fa
terminare il thread ClientConnectionHandler spontaneamente. In seguito viene avviata una
procedura iterativa che una dopo l’altra chiude tutte le finestre aperte e rimuove tutti i talk
dall’omonimo vettore. Dopo che l’utente ha dato l’“OK” sulla
finestra di dialogo tutte le finestre aperte vengono chiuse e la
musichetta si interrompe poiché viene chiamata la system.exit.
Quando l’utente preme il pulsante “Cambia Utente” del menù principale l’itinere seguito è lo
stesso di quando viene richiesto la “disconnessione” eccetto per il fatto che non viene chia-
mata la system.exit finale e quindi dopo aver premuto l’“OK” si ritorna al punto di partenza
in cui viene visualizzata la finestra associata alla classe MYJFrameLogin.
Quando l’utente preme il pulsante “Contatta User” o “Lista canali” vengono richiamate le
funzioni di RaidayClient entraStanza e contattaUtente rispettivamente. Queste due funzioni
sono tra loro molto simili: entrambe dopo aver lanciato un segnale acustico impostano la
modalità d’utilizzo della
classe comune
MyJFCUtente. Dopo
averla resa visibile vengono
chiamate le funzioni
setComeEntraStanza o
setComeContattaUtente
rispettivamente.
Successivamente, con la
chiamata della funzione creaMTMConnection, entrambe le funzioni creano una
Chat HELP DESK su HTTP
46
MTMConnection verso il Server grazie alla quale viene fatta una richiesta(lista delle stanze o
lista degli utenti connessi). Dopo ciò, l’onere gestire la finestra gui, contenente l’elenco
richiesto dall’utente, è affidato all’oggetto jFCUtente, che è un’istanza della classe
MyJFCUtente. Su di esso vengono invocate le funzioni compilaListaStanza e
compilaListaUtenti rispettivamente. Anche queste due funzioni sono molto simili tra loro
poiché la classe di tipo finestra MyJFCUtente è la medesima per entrambe. Esse sono
costituite da un ciclo while, che in base alle informazioni ricevute dal Server sulla
MTMConnection, riempie il vettore data con la lista d’informazioni precedentemente
richiesta. Fatto ciò viene richiamato il metodo repaint dell’oggetto JListListaUtenti che come
dice il nome è una JList. È questo componente grafico che rende visibile una comoda lista
selezionabile col mouse, poiché vi è associato un MouseListener. Nel caso venga premuto il
pulsante “Annulla” si ritorna al menu principale; nel caso vengano premuti i pulsanti “Entra”
o “Contatta”, delle due differenti finestre, allora si accede rispettivamente ad una
Stanza(conversazione multiutente) oppure a una Conversazione Privata.
44..66 LLAA CCOONNVVEERRSSAAZZIIOONNEE PPRRIIVVAATTAA La classe Java scheletro della conversazione privata è TalkSingolo. Infatti per ogni con-
versazione privata aperta viene mandato in esecuzione un thread istanza di questa classe.
Quando viene invocato il costruttore di tale classe viene inizializzata e resa visibile
l’interfaccia grafica della conversazione privata contenuta nella classe Java MyJFTal-
kSingolo. Inoltre viene creato un oggetto istanza della classe Java TalkReceiver.
La classe d’interfaccia grafica ha la medesima inizializzazione e struttura delle altre classi
gui viste in precedenza eccetto che per una cosa: a differenza delle altre classi il suo
contenuto non è statico. Con ciò voglio dire che premendo i pulsanti “Lavagna” e “Dialogo”
la finestra cambia aspetto. A seconda dello stato precendente viene reso visibile l’uno o
l’altro componente grafico rispettivamente associati agli oggetti: JAppletLavagna e
MyScrollPane.
La classe Java TalkReceiver inizializzata con costruttore TalkReceiver(TalkSingolo
talkSorgenteSM) è dedicata al parsing della connessione entrante per una conversazione
privata. Con una serie di if viene confrontato il valore ricevuto con alcuni comandi:
o %$Coordinata%$ clear viene invocata la funzione cancellaLavagna(true) di
Talk singolo perché è stata richiesto da un utente remoto
che essa venga cancellata;
Chat HELP DESK su HTTP
47
o %$Coordinata%$... viene invocata più volte la funzione estrai(che richiama
accorcia) di TalkReciver per estrarre e decodificare le
linee trasmesse in formato stringa, che sono state dise-
gnate dall’utente remoto sulla sua lavagna. Poi con
l’invocazione della funzione drawLine esse vengono ri-
disegnate così com’erano sulla lavagna locale;
o *!*!*!*!*!*!*... Vuol dire che è stato ricevuto un file o una slide: viene
mandato in esecuzione un segnale acustico e visualizzato
un messaggio di avviso nella finestra di conversazione
MyScrollPane;
o “altre cose” Vuol dire che è stato ricevuto un messaggio di tipo testo
semplice e il suo contenuto viene mostrato all’utente
grazie al componente grafico MyScrollPane.
In particolare la
funzione accorcia
ottiene come
parametro in
ingresso la stringa
da manipolare,
restituendone
un’altra, senza la
parte che riguarda
l’ultima coordi-
nata.
Vediamo ora
come reagisce il
codice Java in seguito alle principali azioni utente catturate dagli ActionListeners della fi-
nestra di conversazione privata.
4.6.1 INVIO DI UN MESSAGGIO DI TESTO Se il cursore è posizionato nella zona di scrittura di un messaggio(il JTextField input) e
viene premuto il tasto “Enter” oppure se si fa click col mouse sul pulsante “invia” viene
invocata la funzione inviaMessaggio della classe SendMessage. Questa funzione controlla
Chat HELP DESK su HTTP
48
che il messaggio da inviare non contenga caratteri speciali che potrebbero compromettere il
funzionamento dell’applicazione, apre una “STMConnection” verso il Server e vi invia i
dati.
4.6.2 FILECHOOSER E IMAGECHOOSER Quando vengono premuti i pulsanti “Manda-Slide” o “Manda-File” della finestra gui
associata alla conversazione privata vengono richiamate le funzioni della classe
MyJFTalkSingolo BottoneVisualizzaMousePressed e BottoneMandaFileMousePressed
rispettivamente. Dopo aver prodotto un suono, entrambe rendono visibile un’ulteriore
finestra gui che conferisce all’utente la facoltà di selezionare un file scegliendolo dal disco
rigido del proprio computer. Tale finestra fa parte delle librerie predefinite Java 1.4.2 e la
classe ad essa associata è fileChooser. Dopo che il file è stato selezionato, tale classe
ritorna un oggetto di tipo file che
viene poi passato alla classe padre
TalkSingolo. Su questa vengono poi
invocate i metodi visualizzaSlide e
mandaFile rispettivamente che
provvedono alla trasmissione dei dati.
Il fileChooser per la selezione delle
immagini ha delle funzionalità in più
rispetto a quello per la scelta dei files.
Il package fileChooser contiene un insieme di classi che estendono le funzionalità di
base della classe fileChooser predefinita in Java 1.4.2. Tali funzionalità sono aggiunte
tramite le seguenti righe di codice della funzione BottoneVisualizzaMousePressed: fc.addChoosableFileFilter(new ImageFilter());
fc.setFileView(new ImageFileView());
fc.setAccessory(new ImagePreview(fc));
Gli oggetti istanziati risalgono da classi Java del package fileChooser.
La classe ImageFilter permette di visualizzare nell’elenco solo i files corrispondenti ai
tipi d’immagini supportati dal visualizzatore.
La classe ImageFileView permette di visualizzare nell’elenco i files corrispondenti ai
tipi d’immagini supportati con un’icona diversa da quella predefinita.
Chat HELP DESK su HTTP
49
La classe ImagePreview permette di
visualizzare a destra dell’elenco dei files
un’anteprima miniaturizzata del files che
si seleziona con il mouse, prima che
questo venga inviato. Tale funzione
sfrutta la nota funzione predefinita Java
paintComponent(Graphics g) di
cui si fa overriding.
4.6.3 INVIO E RICEZIONE DI UN FILE Per ogni file che si desidera trasmettere viene avviato un thread a bassa priorità istanza della
classe FileSender, interna alla classe Java TalkSingolo. Questo thread provvede innanzi
tutto a creare un indicatore d’avanzamento visibile all’utente istanziando la classe Java
ProgressMonitorSF del package progressmonitor. Poi grazie alla funzione
creaFileManagerConnection viene creata una connessione al thread del Server che si
occupa di gestire i files e su di essa vengono inviati i dati identificativi dell’utente. Si entra
quindi in un ciclo while munito di timeout che, eseguendo ripetute write, invia tutti i dati
letti dal corpo del file in formato byte sulla connessione. Ad operazione terminata
l’indicatore d’avanzamento scompare, viene chiuso il canale verso il Server e notificato
all’utente la fine del trasferimento dei dati grazie al componente grafico MyScrollPane.
D’altro canto per ogni Client che manda un file ci deve essere un altro Client aperto che
riceve il file. I dati inviati al Server, grazie al meccanismo spiegato nella sezione 3.2,
iniziano ad arrivare direttamente sulla connessione passata thread istanza della classe Java
FileProcessor. Vengono letti “Mittente”, “Nome File” e “Dimensione” dunque viene
creato un indicatore d’avanzamento visibile all’utente istanziando la classe
ProgressMonitorRF del package progressmonitor. Si entra quindi in un ciclo
while con timeout che, eseguendo ripetute read, legge tutti i dati in arrivo facenti parte del
corpo del file in formato byte, sulla connessione. Ad operazione terminata l’indicatore
d’avanzamento scompare, viene chiuso il canale verso il Server e notificato all’utente
l’avvenuta ricezione dei dati grazie visualizzando un messaggio di notifica sul componente
grafico MyScrollPane.
Chat HELP DESK su HTTP
50
4.6.4 INVIO E RICEZIONE DI UNA SLIDE D’altro canto per ogni Client che manda una slide ci deve essere un altro Client aperto che
riceve la slide. I dati inviati al Server, grazie al meccanismo spiegato nella sezione 3.2,
iniziano ad arrivare direttamente sul thread istanza della classe Java SlideProcessor.
Vengono letti “Mittente”, “Nome File” e “Dimensione” dunque viene creato un indicatore
d’avanzamento visibile all’utente istanziando la classe ProgressMonitorRS del package
progressmonitor. Si entra quindi in un ciclo while con timeout che, eseguendo ripetute
write, legge tutti i dati in arrivo, facenti parte del corpo del file in formato byte sulla
connessione. Ad operazione
terminata l’indicatore
d’avanzamento scompare, viene
chiuso il canale verso il Server e
notificato all’utente l’avvenuta
ricezione dei dati grazie al
componente grafico MyScrollPane.
Per finire la slide appena ricevuta
viene visualizzata solo sulla
lavagna locale chiamando ancora
la funzione visualizzaSlide(true). Il valore booleano dell’argomento di tale funzione
specifica dunque se la visualizzazione debba essere fatta solo in locale o anche in remoto.
4.6.5 PROGRESS MONITOR Il package progressMonitor contiene quattro classi: ProgressMonitorSF,
ProgressMonitorRF, ProgressMonitorSS, ProgressMonitorRS. Sono tutte
molto simili tra loro eccetto il fatto che vengono
utilizzate da thread diversi e quindi devono visualizzare
messaggi diversi riguardanti il download e l’upload di
files e slides. Di default è impostato che tali finestre
appaiano immediatamente non appena viene avviato il trasferimento dati. Ogni 100
millisecondi la funzione step controlla che il trasferimento dati non sia terminato o che non
sia stato interrotto dal thread padre del progressMonitor. Infatti le quattro classi di tipo
progressMonitor suddette hanno come classe padre rispettivamente le classi Java:
TalkSingolo, FileProcessor, TalkSingolo e SlideProcessor. Esse sono
Chat HELP DESK su HTTP
51
dotate della funzione isDone, per controllare l’effettivo completamento del trasferimento
dati e della funzione setStop, per interrompere il trasferimento dati in qualunque momento.
Quest’ultima è chiamata quando risulta vera la valutazione booleana: progressMonitor.isCanceled() || fileProcessor.isDone()
cioè quando l’utente ha fatto click sul tasto “Annulla” della finestra dell’indicatore
d’avanzamento oppure quando il trasferimento dei dati è effettivamente terminato.
4.6.6 DISEGNO SULLA LAVAGNA La lavagna viene istanziata grazie alla funzione preparaApplet della finestra gui.
Per disegnare sulla lavagna basta trascinare su di essa il cursore del mouse tenendo premuto
il tasto sinistro. Al rilascio del tasto le linee tracciate vengono codificate in formato stringa,
inviate all’altro utente con cui si sta conversando e quindi ridisegnate sulla sua lavagna.
La classe Java ImageBoard, che estende la classe Applet predefinita in Java, è il cuore
della lavagna, sia per la conversazione
privata sia per quella multiutente. I
metodi mouseDown, mouseDrag e
mouseUp, di cui si fa override, servono
a catturare e visualizzare il disegno in
locale. Nel frattempo che si disegnano le
linee, si provvede alla composizione
della stringa che rappresenta tale linea.
Le linee sono composte da piccoli
segmenti, che interpolano punti successivi. Questa scelta è stata necessaria, in quanto non è
conveniente memorizzare tutti i punti tracciati con il mouse. La struttura di ogni segmento è
la seguente: last_x+","+last_y+","+x+","+y+“;”. Ogni segmento è diviso dal
carattere “;”. Questa codifica è molto importante, in quanto permette di decodificare la
stringa in maniera univoca. L’operazione appena descritta è implementata nel metodo
mouseDrag. Nel metodo mouseDown, richiamato quando si preme il mouse, si aggiunge
l’intestazione della stringa. All’invocazione del metodo mouseUp, si provvede a richiamare
un altro metodo, inviaPunti, che serve a trasmettere i disegni da un Client ad un altro. La
funzione riscriviPunto serve per visualizzare un disegno ricevuto da un Client remoto.
Quest’ultima richiama la funzione creaSTMConnection di ClientConnectionCenter grazie
alla quale trasmette le linee al Server che a sua volta le ritrasmette all’altro Client. Le linee
inviate e ricevute, per non andare perse dopo il repaint, vengono immagazzinate in un
Chat HELP DESK su HTTP
52
vettore fino alla cancellazione della lavagna. Ciò è spiegato dettagliatamente nella sezione
“Problemi e Soluzioni”.
4.6.7 CANCELLAZIONE DELLA LAVAGNA Quest’operazione può essere richiesta sia direttamente, premendo il tasto “Cancella”, sia
indirettamente, premendo il tasto “Manda-Slide”, perché la lavagna viene pulita prima della
visualizzazione di ogni una nuova slide. Tuttavia l’importante è sapere che in un modo o
nell’altro viene sempre richiamata la funzione cancellaLavagna(boolean val). Se il valore
booleano val vale true viene cancellata solo la lavagna locale, se invece val vale false
vengono cancellate contemporaneamente la lavagna locale e quella remota dell’utente con
cui si sta conversando. Ciò viene fatto grazie alla funzione creaSTMConnection che apre
una connessione verso il Server. Sul canale viene mandato un messaggio speciale contenente
il testo “%$Coordinata%$ clear”. Dall’altro lato, quando il thread istanza della classe
TalkReciver associato ad uno specifico destinatario riceve un messaggio con tale testo
esso richiama la funzione cancellaLavagna(true) contenuta nell’istanza della classe Java
TalkSingolo ad esso associata.
44..77 LLAA CCOONNVVEERRSSAAZZIIOONNEE MMUULLTTIIUUTTEENNTTEE NNEELLLLEE SSTTAANNZZEE Il principio di base della conversazione multiutente è che ogni messaggio, inviato da qualun-
que utente nella stanza, deve essere rispedito così com’è a tutti gli utenti della stanza. Natu-
ralmente, oltre ai messaggi di testo, devono essere rispediti a tutti gli utenti della stanza an-
che tutti i disegni fatti sulle lavagne e tutte le notifiche d’utenti che si collegano e si scolle-
gano. Questo è indispensabile per mantenere sempre aggiornata la lista degli utenti connessi
visibile sul lato destro delle finestre conversazioni multiutente di ciascun partecipante. Ciò
risulta abbastanza naturale in un’architettura come questa in cui tutti i messaggi e i dati pas-
sano necessariamente per il Server prima di raggiungere il Client di destinazione.
La classe Java scheletro della conversazione privata è TalkMultiUtente. Infatti per ogni
conversazione multiutente aperta è mandato in esecuzione un thread istanza di questa classe.
Quando viene invocato il costruttore di TalkMultiUtente viene inizializzata e resa visibile
l’interfaccia grafica della conversazione multiutente contenuta nella classe Java
MyJFMultiUtente ed inoltre viene creato un oggetto istanza della classe Java
TalkReceiver.
Chat HELP DESK su HTTP
53
La classe d’interfaccia grafica ha la medesima modalità d’inizializzazione e la struttura delle
altre classi gui viste in
precedenza. Il sistema di
visualizzazione dei
messaggi e la lavagna
sfruttano gli stessi
componenti grafici della
chat privata. Sul lato
sinistro della finestra è
posizionata la lista degli
utenti ottenuta con uno
ScrollPanel chiamato
ScrollPaneListOutputUtenti. Ad esso è associato un MouseListener: quando si fa
velocemente doppio click col mouse sul nome di un utente collegato viene richiamata la
funzione chatPrivata, della classe Java TalkMultiUtente. Questa apre una
connessione(precisamente una MTMConnection) col Server. Ciò avvia la sopra citata
procedura che porta alla creazione di una nuova conversazione privata tra l’utente
selezionato e l’utente locale.
La classe Java TalkReceiver, inizializzata con costruttore TalkReceiver(TalkMultiUtente
talkSorgenteMM), è dedicata al parsing della connessione entrante per una conversazione
privata. Essa funziona nello stesso identico modo come se utilizzata in una conversazione
privata eccetto per il fatto che in questo caso è collegata alla classe TalkMultiUtente.
4.7.1 INVIO E RICEZIONE DI UN MESSAGGIO DI TESTO Se il cursore è posizionato nella zona di scrittura di un messaggio(il JTextField input)
viene premuto il tasto “Enter” oppure se si fa click col mouse sul pulsante “invia” viene
invocata la funzione inviaMessaggio della classe SendMultipleMessage. Questa
funzione controlla che il messaggio da inviare non contenga caratteri speciali che potrebbero
compromettere il funzionamento dell’applicazione, apre una “MTMConnection” verso il
Server e v’invia i dati. Questa volta però il thread di destinazione sul Server è diverso: esso,
infatti, è il multiTalkManagerThread. Questo thread ha il compito di inoltrare il messaggio
ricevuto a tutti gli utenti della stanza inviando tanti semplici messaggi quanti sono gli utenti
che sono collegati.
Chat HELP DESK su HTTP
54
È scontato che per ogni Client aperto che manda un messaggio in una stanza ci deve essere
almeno un Client in ascolto che legge tale messaggio, cioè il Client stesso che l’ha mandato.
Chiunque mandi un messaggio in una stanza deve poter visualizzare nella finestra di
conversazione il messaggio che lui stesso ha appena inviato. La ricezione del messaggio è
affidata alla classe Java TalkReciver la cui istanza è agganciata ad un’istanza della
classe Java TalkMultiUtente. Dopo aver fatto il parsing il messaggio di testo viene
appeso in coda agli altri messaggi della stanza e visualizzato sullo ScrollPanel
ScrollPaneListOutputUtenti associato alla Jlist JListOutputUtenti.
4.7.2 DISEGNO SULLA LAVAGNA Il funzionamento della Lavagna è concettualmente lo stesso di quello utilizzato per la
conversazione privata eccetto che per una cosa. Si ricordi che ogni linea disegnata sulla
lavagna altro non è uno speciale messaggio di testo, con prefisso “%$Coordinata%$”. Esso
viene spedito dalla classe ImageBoard al thread del Server dedicato allo smistamento dei
messaggi. Ebbene in questo caso il thread di destinazione sul Server invece di essere il
SingleTalKmanagerThread è il MultiTalkManagerThread che, come prima detto, inoltra
ogni messaggio ricevuto a tutti i destinatari della stanza. L’effetto è quello voluto: ogni linea
tracciata su una qualunque delle lavagne degli utenti partecipanti su una stanza, viene
trasmessa e ridisegnata sulle lavagne di tutti gli utenti partecipanti alla conversazione.
Il cambiamento di modalità per questo duplice utilizzo della classe ImageBoard può
essere facilmente impostato tramite il valore booleano della variabile tsm passata al
costruttore di tale classe.
4.7.3 CANCELLAZIONE DELLA LAVAGNA Per quanto riguarda la cancellazione della lavagna vale lo stesso identico discorso fatto per
la conversazione privata, eccetto il fatto che questa la lavagna delle stanze multiutente non è
abilitata alla visualizzazione delle slides.
Vorrei ricordare che, ad ogni pressione del pulsante “Cancella”, viene inviato dalla classe
TalkMultiutente uno speciale messaggio di testo, col prefisso “%$Coordinata%$
clear”, al thread MultiTalkManagerThread che sta girando sul Server. Automaticamente tale
messaggio viene inoltrato a tutti gli utenti della stanza e, con modalità già note, vengono
contemporaneamente cancellate le lavagne di tutti i partecipanti alla conversazione.
Chat HELP DESK su HTTP
55
55 LL’’AAPPPPLLIICCAAZZIIOONNEE SSEERRVVEERR Prima di iniziare una descrizione approfondita dell’applicazione Server è bene chiarire che le
classi del package exception e del package net sono identiche a quelle usate
nell’applicazione Client e per questo non verranno descritte nuovamente.
Anche la classe ServerConnectionCenter è strutturalmente simile alla classe
ClientConnectionCenter già vista. Il suo schema di funzionamento e i suoi codici
d’interfacciamento con il Client sono stati già stati descritti perciò questa classe non subirà
ulteriori descrizioni.
55..11 LLAA FFAASSEE DDII IINNIIZZIIAALLIIZZZZAAZZIIOONNEE La classe principale che deve essere mandata in esecuzione è RaidayServer. Come nel
Client, i valori delle variabili d’istanza di questa classe permettono di manipolare i parametri
fondamentali dell’applicazione.
Per iniziare viene istanziato un oggetto statico della classe Java OJDBCConnection. Que-
sta classe inizializza il “sun.jdbc.odbc.JdbcOdbcDriver” che permette, tramite il driver di
Microsoft Access, il collegamento al file accounts.mbd. Questo è il file database che memo-
rizza permanentemente su disco gli utenti registrati sul Server con le relative passwords.
Questo file immagazzina e tiene traccia di tutti i dati delle registrazioni avvenute nella ses-
sione corrente e in quelle precedenti. In particolare la funzione getOJDBCConnection resti-
tuisce il collegamento alla fonte dati ODBC.
Poi viene inizializzato il database online istanziando la classe Java OnlineDB. Questa a sua
volta inizializza il thread Database che gestisce le connessioni ODBC ed ha accesso al file
accounts.mdb. Con la chiamata della funzione caricaDatabase i dati vengono letti da questo
file e caricati nel database online per riempire i vettori ONDBNomi e ONDBPassword. Inol-
tre vengono inizializzate a null le posizioni con lo stesso indice degli altri cinque vettori
dell’istanza della classe Java OnlineDB.
Successivamente viene istanziato un oggetto della classe ServerConnectionHandler e
mandato in esecuzione come thread. Si tratta di un thread ad altissima priorità che ha l’unico
compito accettare le connessioni entranti da parte dei Clients, di qualunque tipo esse siano, e
di passarle ad un altro thread a priorità normale: il ServerConnectionDeliver.
Dopo di che viene attivato un thread istanza della classe Java pingServer, che, come dice
il nome, ha il compito di monitorare la connessione degli utenti che risultano online.
Chat HELP DESK su HTTP
56
Infine viene caricata una semplicissima interfaccia grafica istanziando la classe Java
ServerMainFrame, unica classe del package
gui che estende la classe JFrame predefinita
in Java. L’unico componente di questa finestra è
un bottone “Termina” capace di far terminare
immediatamente l’esecuzione del Server.
55..22 IILL DDAATTAABBAASSEE OONNLLIINNEE Un’istanza della classe Java OnlineDB può considerarsi un vero e proprio database caricato
in memoria RAM. Essa archivia le MainConnection, la lista degli usernames e delle relative
passwords, le connessioni vergini, è collegata al thread Database. Essa ha quindi il potere
di mutare lo stato di collegamento di ogni Client connesso al Server e dunque di validare le
re/deregistrazioni.
Il nucleo del database è fatto da sette vettori messi in parallelo, una specie di matrice. Le in-
formazioni relative ad un particolare Client si trovano tutte sullo stesso indice trasversalmen-
te ai vari vettori secondo uno schema di questo tipo:
Client 0 Client 1 Client 2 ... … Client n
Nome Vettore ↓ ↓ ↓ ↓ ↓ ↓
ONDBNomi tizio
ONDBPassword tizio
ONDBMainConnection MainConn
ONDBMainPrintWriter PW
ONDBServerConnectionCenter scc
ONDBReadyConnection Connection
ONDBReadyBufferedReader BR
Per ogni utente il primo e il secondo vettore contengono l’username e la password usate per
la registrazione. Il terzo vettore contiene un riferimento alla stabile MainConnection e il
quarto vettore un oggetto PrintWriter ad essa associato. Il quinto vettore contiene un riferi-
mento ad un ServerConnectionCenter preconfigurato per connettersi a quel determi-
nato Client. Se il Client in questione è connesso in modalità IP Pubblico, i vettori sei e sette
sono vuoti. Altrimenti, se il Client in questione è connesso in modalità IP Privato, i vettori
Chat HELP DESK su HTTP
57
sei e sette contengono rispettivamente un vettore di connessioni vergini pronte all’uso e un
vettore di BufferedReader agganciati a tali connessioni.
La classe Java associata al database online possiede una serie di funzioni di routine che ne
permettono la gestione in maniera rapida e semplice: aggiungiReadyConnection,
aggiungiUser, ciSonoReadyConnection, collegamentoUtente, collegamentoUtenteADV,
disconnessioneUtente, getHowMuchUsersAreOnline, getMainConnection, isInDB,
prelevaReadyBufferedReader, prelevaReadyConnection, rimuoviUser. Il nome stesso è già
sufficiente come commento per esplicare il comportamento di molti di questi metodi; basti
sapere che tutti quanti fanno una serie di operazioni elementari, spesso parallelamente, sui
sette vettori sopra citati. Tuttavia le funzionalità di molti questi metodi sono successivamente
descritte nel seguito, per meglio comprendere come avvenga lo smistamento delle
connessioni entranti.
55..33 LLOO SSMMIISSTTAAMMEENNTTOO DDEELLLLEE CCOONNNNEESSSSIIOONNII EENNTTRRAANNTTII Non appena la classe ServerConnectionHandler ha ottenuto un socket proveniente da
un Client, questo viene passato al thread ServerConnectionDeliverThread ed il
ServerConnectionHandlerThread si rimette immediatamente in ascolto per accettare nuove
eventuali richieste di connessione. Il ServerConnectionDeliverThread inizia a leggere i dati
provenienti dal Socket. A seconda del comando ricevuto le connessioni vengono smistate tra
i seguenti thread: Database, SingleTalkManager, MultiTalkManager,
Slidemanager, FileManager oppure la connessione o viene affidata ad una tra le due
funzioni manageMainConnection o managementConnection oppure viene subito chiusa.
Come per il Client, l’esistenza della strana funzione readline nella classe
ServerConnectionDeliver è motivata nella sezione “problemi e soluzioni”.
5.3.1 REGISTRAZIONE E DEREGISTRAZIONE Quando la connessione viene passata al Thread database possono essere richieste due
operazioni: la registrazione di un nuovo utente e la deregistrazione di un utente esistente.
Nel primo caso viene invocata una query SQL del tipo “INSERT INTO” sul driver ODBC
per inserire i dati su disco. Se questa operazione è andata a buon fine, per mantenere
aggiornato e non far perdere consistenza al database online, viene invocata su di esso il
metodo aggiungiUser. Nel secondo caso viene invocata una query SQL del tipo “DELETE
FROM” sul driver ODBC per rimuovere i dati dal disco. Se questa operazione è andata a
Chat HELP DESK su HTTP
58
buon fine, per mantenere aggiornato e non far perdere consistenza al database online, viene
invocata sull’istanza classe Java OnlineDB il metodo rimuoviUser.
5.3.2 LOGIN E LOGOUT DI UN CLIENT Il Login di un Client è affidato alla funzione manageMainConnection del thread
ServerConnectionDeliverThread. Inizialmente vengono acquisiti username,
password, modalità di connessione(connessione diretta o tipo di proxy utilizzato), indirizzo
IP del proxy e sua porta di ascolto (in caso di connessione diretta arrivano due stringhe
vuote insignificanti), modalità di collegamento ad IP Pubblico o IP Privato del nuovo Client.
A questo punto viene istanziato e configurato un ServerConnectionCenter, e viene
controllato tramite il database online, grazie alla funzione getHowMuchUsersAreOnline, che
siano connessi meno di 100 utenti. Se così non è l’utente viene espulso col messaggio
“Server Full” che apparirà in una finestra di dialogo visibile all’utente in questione dal lato
client. Se c’è posto viene controllato che l’utente non risulti già collegato con la funzione
isOnline e che sia rigorosamente registrato con gli username e password inviati grazie alla
funzione isInDB_PSW. Se tutto va a buon fine l’utente viene accettato. Poi viene istanziato
il ProxyInfo della classe ServerConnectionCenter e i sette vettori del database
online vengono riempiti con le informazioni indispensabili raccolte all’inizio della fase di
Login. Nel caso qualcosa va storto l’utente viene espulso con un messaggio esplicante il
motivo del rifiuto. Esso apparirà nella consueta finestra di dialogo visibile dal lato client.
Il Logout viene richiesto dal lato client inviando alla funzione managementConnection del
thread ServerConnectionDeliverThread il codice “13”. In questo caso viene
semplicemente invocata la funzione disconnessioneUtente(username) del database online.
Essa provvede a rimuovere tutte le informazioni archiviate nei sette vettori all’indice di
posizione occupata nel vettore ONDBNomi dalla voce username passatale.
5.3.3 MESSAGGI DELLE CONVERSAZIONI PRIVATE Tutti i messaggi di conversazione privata provenienti da un Client e destinati ad un altro
Client sono affidati ad un istanza della classe Java SingleTalkManager, mandata in
esecuzione come thread. Quando questa classe viene istanziata richiede nel suo costruttore
un riferimento al database online.
Quando una connessione entrante viene smistata dal ServerConnectionDeliver ad
un thread istanza della classe Java SingleTalkManager, ci si aspetta che dalla
Chat HELP DESK su HTTP
59
connessione arrivino in sequenza il mittente, il destinatario e il corpo del messaggio stesso.
Quindi, facendo richiesta al database online con la funzione
onlineDB.isOnline(destinatario), viene controllato se il “destinatario” sia effettivamente
collegato. Potrebbe per esempio capitare che mentre il messaggio viene spedito il
destinatario sia collegato, ma prima che il messaggio giunga a destinazione il destinatario si
sia disconnesso. A questo punto viene creata la connessione al MessageProcessor
utilizzando il ServerConnectionCenter del destinatario prelevato dal database
online. Potrebbe anche capitare che il destinatario sia andato in timeout. Questa eventualità
viene contemplata catturando l’eventuale eccezione scaturita durante la creazione della
connessione verso il destinatario stesso o durante l’invio dei dati su tale connessione.
Insomma, nel caso il messaggio non possa essere recapitato al destinatario, questo viene
anche automaticamente disconnesso automaticamente dal Server e dichiarato offline. Per di
più viene inviato il codice /*ko*/ indietro al Client mittente nella cui finestra di
conversazione privata appare un messaggio che comunica l’avvenuta disconnessione del
destinatario. Se invece non si verificano problemi i dati mittente e messaggio vengono
recapitati al Client destinatario. Infine le connessioni con entrambi i Client vengono chiuse.
5.3.4 MESSAGGI DELLE CONVERSAZIONI MULTIUTENTE NELLE STANZE
Tutti i messaggi di conversazione privata provenienti da un Client e destinati ad un altro
Client sono affidati ad un istanza della classe Java MultiTalkManager, mandata in
esecuzione come thread. Quando questa classe viene istanziata richiede nel suo costruttore
un riferimento al database online.
Quando una connessione entrante viene smistata dal ServerConnectionDeliver ad
un thread istanza della classe Java MultiTalkManager, ci si aspetta che dalla
connessione arrivino in sequenza, l’operazione, il mittente, il destinatario e il corpo del
messaggio stesso, che sono poi immagazzinati in variabili omonime.
A questo punto viene istanziato un oggetto della classe ServerConnectionCenter in
questo modo: “serverConnectionCenter = new
ServerConnectionCenter(serverPort);”. Ciò provoca l’invocazione dell’altro
costruttore di questa classe. In questo modo l’oggetto serverConnectionCenter viene
configurato come centro di controllo per le connessioni dirette dal Server indietro sul Server
stesso, precisamente sulla porta 80. In questa modalità infatti diventa operativa la funzione
Chat HELP DESK su HTTP
60
creaLoopBackSTMConnection della classe Java ServerConnectionCenter. Inviando
dati su questa connessione è possibile sfruttare la classe SingleTalkManager del Server
per mandare un messaggio di testo ad un utente che ha una conversazione multiutente
aperta. Se ciò venisse fatto per tutti gli utenti di una stanza allora si avrebbe l’effetto
desiderato: una conversazione multiutente in cui ogni messaggio inviato da un utente
qualunque raggiunge tutti i partecipanti. È ora doveroso precisare che ogni Stanza esistente
sul Server è rappresentata da un’istanza della classe Java Canale. Essa archivia il nome
della Stanza a cui è associata e i nomi di tutti gli utenti ad essa connessi. Grazie alle funzioni
addUser e delUser è possibile aggiungere e rimuovere partecipanti. Il metodo getUsers,
invece, restituisce un comodo vettore contenente l’elenco di tutti gli utenti partecipanti a
quella Stanza.
Ritornando alla classe MultiTalkManager, dopo aver istanziato il
ServerConnectionCenter viene valutato il contenuto della variabile operazione.
Se operazione vale “SendM” allora viene sfruttato il criterio e la tecnica appena descritti:
grazie ad un ciclo for i dati mittente, destinatario e messaggio vengono inviati ai
SingleTalkManager che inviano mittente e messaggio a tutti gli utenti della Stanza.
Se operazione vale “lStanze” grazie ad un ciclo for intorno al vettore listaStanze, variabile
d’istanza della classe MultiTalkManager, viene generata e spedita all’utente la lista
delle stanze aperte. A tale scopo è utilizzato l’OutputStream della connessione in ingresso al
MultiTalkManager stesso.
Se operazione vale “mTalk” viene controllato se il nome della stanza ricevuta esiste già nel
vettore listaStanze: se esiste l’utente richiedente viene aggiunto alla lista degli utenti
connessi nell’oggetto Canale corrispondente, altrimenti viene istanziato un nuovo oggetto
di tipo Canale e aggiunto al vettore listaStanze. Dopo di ciò con altri due cicli for viene
composta sotto forma di stringa concatenata la lista degli utenti partecipanti alla stanza in
questione, naturalmente aggiornata col nome dell’ultimo arrivato. Questa lista, sfruttando la
funzione creaLoopBackSTMConnection della classe Java ServerConnectionCenter
viene spedita a tutti i partecipanti. In questomodo tutti percepiscono l’ingresso di un nuovo
utente.
Se operazione vale “exit”, come prima visto, viene ricomposta sotto forma di stringa
concatenata la lista dei partecipanti escludendo il nome dell’utente che sta lasciando la
stanza. Questa lista, sfruttando la funzione creaLoopBackSTMConnection della classe Java
ServerConnectionCenter viene spedita a tutti i partecipanti che percepiscono l’uscita di
un utente. Con l’ultimo if viene controllato se la stanza non si è svuotata totalmente con
Chat HELP DESK su HTTP
61
l’uscita dell’utente che ha richiesto la exit. Se la stanza risulta essere vuota l’oggetto Canale
ad essa associato viene rimosso dal vettore listaStanze e il riferimento ad esso viene perso: la
stanza viene definitivamente chiusa.
Se operazione vale “Priv” viene inviato un messaggio particolare dal
MultiTalkManager. A tal fineesso sfrutta la funzione creaLoopBackSTMConnection
della classe Java ServerConnectionCenter che si aggancia al SingleTalkManager. Il
messaggio inviato ha la facoltà di far apparire, solo per il destinatario selezionato col doppio
click dal Client mittente sulla lista degli utenti partecipanti ad una stanza, una nuova finestra
di conversazione privata iniziata dall’utente mittente. Da lì a poi questi due utenti possono
continuare a chattare in modalità conversazione privata sulle rispettive finestre.
5.3.5 DISEGNI E CANCELLAZIONE DELLE LAVAGNE Come già visto le linee sono inviate come stringhe in messaggi speciali con il suffisso
“%$Coordinata%$”. Anche l’operazione di cancellazione della lavagna altro non è che un
messaggio speciale con il suffisso “%$Coordinata%$ clear”. Ebbene tali messaggi vengono
trattati dal Server come fossero normali messaggi di conversazione nelle modalità appena
viste nei due paragrafi precedenti. Anche il sistema di archiviazione dei messaggi nel vettore
linee è ancora valida.
5.3.6 RICEZIONE E INOLTRO DEI FILES Quando una connessione entrante viene smistata dal ServerConnectionDeliver ad
un thread istanza della classe Java FileManager, ci si aspetta che dalla connessione
arrivino in sequenza, il mittente, il destinatario, il nome del file e la sua dimensione, che
sono poi immagazzinati in variabili omonime.
Se il destinatario risulta essere online gli viene inviato un messaggio di testo che preavvisa
l’arrivo del file. Poi sfruttando un ciclo while i dati in arrivo dal Client mittente vengono letti
a livello di Byte, un KByte alla volta, e rispediti al Client destinatario. Se per un minuto di
seguito non è possibile trasferire dati viene dichiarato il timeout e il trasferimento viene
annullato. A fine trasferimento vengono chiusi le connessioni con entrambi i Client.
Se invece il destinatario non risulta essere più online oppure si scollega durante il
trasferimento allora viene notificato al Client Mittente che il destinatario si è scollegato. Ciò
viene fatto invocando sull’oggetto istanza della classe ServerConnectionCenter,
Chat HELP DESK su HTTP
62
configurata per il mittente la funzione creaClientHandlerConnection("0"). Sulla
connessione ottenuta viene dunque inviato il codice /*ko*/.
5.3.7 RICEZIONE E INOLTRO DELLE SLIDES La classe Java SlideManager è quella dedicata allo smistamento delle slides. Essa
funziona praticamente allo stesso modo della classe FileManager e ha anche gli stessi
metodi. C’è però una cosa in più: prima di iniziare la ricezione della slides viene inviato un
messaggio di testo speciale al Client destinatario contenente il testo “%$Coordinata%$
clear”. Questo messaggio causa la cancellazione di tutte le scritte presenti sulla lavagna del
Client destinatario prima dell’effettiva visualizzazione della slides che sta per ricevere.
55..44 PPIINNGGIINNGG EE DDIISSCCOONNNNEESSSSIIOONNEE AAUUTTOOMMAATTIICCAA PPEERR TTIIMMEEOOUUTT Abbiamo già visto che lo stato di collegamento di ogni Client è mantenuto aggiornato attra-
verso le MainConnection instaurate da ogni Client all’atto del Login sul Server. Il concetto è
che fino a quando la connessione risulta aperta, e dunque una qualunque operazione su di
essa non genera eccezione, il Client risulta connesso. In più si richiede che la connessione
non sia troppo lenta e quindi quando viene mandata una richiesta di ping ad un Client questo
deve rispondere entro il tempo di timeout: 20 secondi. Se dalla fase di pinging scaturisce
un’eccezione oppure un Client non risponde al ping prima dello scadere del tempo di timeout
esso viene automaticamente disconnesso e dichiarato offline.
Ebbene la classe Java PingServer, che estende la classe Thread predefinita in Java, mette
in pratica il concetto appena esposto. Questa classe ha dei riferimenti alla classe OnlineDB,
grazie alla quale, ottenendo un riferimento ai vettori ONDBNomi e ONDBMainConnection,
si può ottenere la lista degli utenti connessi ed effettuare la disconnessione semplicemente
impostando a null la MainConnection corrispondente. Tutto il corpo di questa classe è con-
tenuto all’interno di un ciclo while(true) che, dopo un’ attesa iniziale di cinque secondi, si ri-
pete continuamente per tutto il ciclo di vita del Server. Poiché questa classe è vitale per il
Server ma il suo funzionamento è messo a dura prova da tutte le possibili situazioni che si
potrebbero verificare ho messo a punto un meccanismo grazie al quale, in caso di crash il
thread PingServer viene automaticamente riavviato:
try{
sleep(attesaIniziale);
while(true)
Chat HELP DESK su HTTP
63
{
. . .
}
} catch (Exception e) {
new PingServer(onlineDB);
}
Grazie ad un ciclo for interno al while(true) viene inviata la richiesta di ping ad ogni Client
collegato. Ad ogni tentativo di ping viene dedicato un ulteriore thread istanza della classe
Java Ping. Il PingServerThread fa join su questo thread: il PingThread si mette in attesa
della risposta al ping da parte del Client, ma se entro 20 secondi questo thread non termina
automaticamente, perché ha ricevuto la risposta, il thread padre PingServerThread lo
uccide e disconnette il Client dichiarandolo una volta per tutte offline.
55..55 LLOO SSHHUUTTDDOOWWNN DDEELL SSEERRVVEERR Per semplicità è stato previsto che il Server non abbia una procedura di terminazione che
comunichi ai vari Client l’imminente spegnimento e quindi la chiusura del Server mentre i
Client sono in esecuzione. Il Server può essere chiuso ottenendo lo stesso risultato sia pre-
mendo il bottone “Termina” della finestra sia premendo la χ in alto a destra comune a tutti i
sistemi operativi windows: in entrambi i casi viene infatti chiamato il metodo
System.exit(0).
Chat HELP DESK su HTTP
64
66 LLAA DDOOCCUUMMEENNTTAAZZIIOONNEE La documentazione dell’applicazione consiste di questo documento e dei files in formato
html contenuti nelle due sottocartelle della cartella Api. Queste contengono, separatamente
per il Client e per il Server, tutti i commenti al codice in formato Javadoc.
Per consultare la documentazione è sufficiente aprire con un browser web i files index.html
contenuti nelle sottocartelle Client e Server di Api.
Chat HELP DESK su HTTP
65
77 BBRREEVVEE MMAANNUUAALLEE PPEERR LL’’UUSSOO
77..11 IISSTTRRUUZZIIOONNII PPEERR LLAA CCOONNFFIIGGUURRAAZZIIOONNEE EE LL’’UUTTIILLIIZZZZOO È preferibile utilizzare questo software su PC con sistema operativo Microsoft Windows XP
con Directx e JRE installati.
Tutte le classi del Client e del Server sono state compilate con Java2 SDK SE versione 1.4.2,
della quale è fornita una copia, insieme alla JRE 1.4.2, sul CD che contiene questo file. Nel
caso si verifichino dei malfunzionamenti si consiglia di installare questa versione, in quanto è
stata utilizzata per la realizzazione di questo software. La compilazione non può avvenire con
versioni precedenti alla 1.3, in quanto non sarebbero riconosciuti alcuni metodi delle classi,
che riguardano il suono la grafica.
Copiare la cartella RaidayHelpDesk_su_HTTP sul disco locale
Togliere il flag sola lettura da tutti i file
Si possono opzionalmente ricompilare tutti i files .java, con la versione di Java in-
stallata sul PC
Ora è necessario configurare il DB, seguendo le seguenti procedure:
o Aprire il Pannello di Controllo ed entrare in Strumenti di Amministrazione.
o Eseguire Origine dati (ODBC)
o Nella finestra DSN Utente fare click su Aggiungi
o Selezionare dall’elenco Microsoft Access Driver
o Nel campo nome origine dati digitare “accounts”
o Fare click su seleziona
o Ricercare il file accounts.mdb nella cartella Server
o Fare click su avanzate
o Immettere Nome Accesso “test” e Password: “test”
Bisogna sempre avviare prima il Server e poi i vari Clients
Per avviare il Server è sufficiente mandare in esecuzione il file batch “Avvia il
Server.bat” contenuto nella cartella RaidayHelpDesk_su_HTTP
Per avviare un Client è sufficiente mandare in esecuzione il file batch “Avvia un
Client.bat” contenuto nella cartella RaidayHelpDesk_su_HTTP
Per cancella re tutti i files ricevuti dai client è sufficiente mandare in esecuzione il fi-
le batch “Elimina immagini e files ricevuti.bat” contenuto nella cartella RaidayHel-
pDesk_su_HTTP
Chat HELP DESK su HTTP
66
77..22 UUNN CCAASSOO DDII TTEESSTT PPEERR LL’’AAPPPPLLIICCAAZZIIOONNEE Il test dell’applicazione può essere effettuato anche su un solo pc, senza necessità di
collegamento Internet o di rete, nel quale verranno avviati il Server e due Client. Se-
guire le seguenti istruzioni:
Mandare in esecuzione la classe RaidayServer. Si può utilizzare il file batch “Avvia il
Server.bat”
Mandare in esecuzione la classe RaidayClient. Si può utilizzare il file batch “Avvia
un Client.bat”
L’indirizzo IP del Server deve essere “localhost” ossia “127.0.0.1”
Fare click su Registra
Si deve udire un suono
Immettere Username “tizio” Password “tizio” (username e password sono uguali per
semplificare)
Fare click su Registrati
Si deve udire un suono
Chiudere la finestra che comunicherà se è stata effettuata l’operazione
Nella finestra di Login immettere di nuovo Username “tizio” Password “tizio”
Chiudere la finestra di dialogo che comparirà.
Si deve udire una voce che dice “User is Online”
Mandare di nuovo in esecuzione la classe RaidayClient. Si può utilizzare il file batch
“Avvia un Client.bat”
Effettuare un’altra registrazione questa volta con Username “caio” e Password
“caio”
Andare nella finestra opzioni e vistare il quadratino per la modalità di collegamento
con IP privato.
Una volta ritornati alla finestra principale immettere di nuovo questi dati ed effettua-
re la connessione.
Chiudere la finestra di dialogo che comparirà.
Si deve udire una voce che dice “User is Online”
Da adesso in poi molti eventi dovranno essere accompagnati da un suono caratteri-
stico
Arrivati al menù principale fare click su Contatta User
Selezionare tizio dall’elenco controllando che questo nome sia comparso nella barra
in basso
Chat HELP DESK su HTTP
67
Fare click su contatta
Una volta apparsa la finestra di Conversazione privata “caio – Conversazione privata
con tizio” scrivere un messaggio nel campo di testo in basso e premere invio.
Controllare che si sia aperta una nuova finestra con il titolo “tizio – Conversazione
privata con caio”.
Verificare nella nuova finestra che il messaggio è arrivato al destinatario.
Fare click col mouse sul pulsante “Lavagna”
Fare click col mouse sul pulsante “Slide”
Selezionare un file di immagine navigando nelle cartelle del vostro hard disk
Fare click su invia
Sulla lavagna verrà visualizzata l’immagine da voi selezionata.
Verificare che nella finestra “tizio – Conversazione privata con caio” sia apparsa la
stessa immagine
Tracciare una linea con il mouse sull’immagine
Verificare che nella finestra “caio – Conversazione privata con tizio” sia comparsa
questa linea.
Fare click col mouse sul pulsante “Cancella” e verificare che le linee disegnate col
mouse siano scomparse in entrambe le lavagna
Fare click sul pulsante “File”
Selezionare un file di grandi dimensioni, almeno 10 Mbyte, navigando nelle cartelle
del vostro hard disk
Fare click su invia
Osservare se appaiono gli indicatori di avanzamento, sia in trasmissione che in rice-
zione.
Andare sulla finestra “tizio – Conversazione privata con caio” e fare click sul pul-
sante “Dialogo”
Verificare che sia apparso il messaggio “ricezione file”
Attendere la fine del trasferimento e verificare che il file sia stato effettivamente ri-
cevuto. Il file viene memorizzato nella cartella il cui percorso viene visualizzato nel-
la finestra di conversazione a ricezione completata
Verificare che il file sia funzionate, se per esempio avete scelto una canzone allora
provate a verificare se la canzone ricevuta sia ascoltabile con Windows Media Player
Chiudere le due finestre di conversazione privata
Ritornare sulla finestra principale del client tizio
Chat HELP DESK su HTTP
68
Fare click su Lista Stanze
Selezionare la Stanza Formia dalla lista controllando che questo nome sia comparso
nella barra in basso
Fare click su entra
Tornare alla finestra principale del client caio
Eseguire la stessa operazione entrando nella stessa stanza Formia
Iniziare una conversazione e disegnare sulla lavagna
Fare doppio click col mouse velocemente sul nome del utente tizio nell’elenco degli
utenti presenti nella stanza Formia
Verificare che siano ricomparse le finestre di conversazione privata tra i due utenti
Provare a mandare qualche messaggio di testo e verificare che il meccanismo di chat
funzioni in entrambi i sensi
Chiudere tutte le finestre di conversazione
Fare click sul pulsante scollegati della finestra principale dell’utente tizio
Si deve udire una musichetta
Chiudere la finestra di dialogo che conferma la disconnessione
Fare click sul pulsante scollegati della finestra principale dell’utente caio
Si deve udire una musichetta
Chiudere la finestra di dialogo che conferma la disconnessione
Andare nella finestra del server e fare click sul pulsante “Termina”
77..33 RREEQQUUIISSIITTII MMIINNIIMMII DDII SSIISSTTEEMMAA Il Client e il Server, che si suppone girino su macchine separate hanno requisiti minimi di si-
stema differenti.
Per il Client sono necessari:
• Sistema operativo che supporti JRE 1.3 e Java Virtual Machine
• Processore Pentium 2 a 300 Mhz
• 256 Mb Ram
• 5 Mb Spazio libero su Hard Disk
• Connessione a Internet o Rete a 56kbps
• Sistema audio Sound Blaster compatibile (opzionale)
Per il Server sono necessari:
• Sistema operativo che supporti JRE 1.3 e Java Virtual Machine
Chat HELP DESK su HTTP
69
• Processore Pentium 3 a 750 mhz
• 256 Mb ram
• 2 Mb Spazio libero su Hard Disk
• Driver DBMS Microsoft Access
• Connessione a Internet o Rete a 2 Mbit con indirizzo IP Pubblico
Chat HELP DESK su HTTP
70
88 PPRROOBBLLEEMMII EE SSOOLLUUZZIIOONNII Quando ho rivisto le classi Java del “progetto di reti di calcolatori”, che dovevo estendere
per fare questa tesi, mi è preso un attimo di sconcerto. Il codice era praticamente
incomprensibile, non perché mal fatto o non indentato ma, perché era disordinato, c’erano
delle classi di 2000 righe e soprattutto non c’erano criteri di ordinamento o packages. Prima
di iniziare a lavorare allora ho deciso di suddividere le classi in packages, di creare classi
nuove snellendo quelle più grosse, di disaccoppiare e modularizzare ove fosse possibile.
Fatto ciò, mi sono reso conto che la Chat del progetto utilizzava più di una porta sia per il
Client che per il Server, invece io potevo utilizzare solo una porta: l’80. Quindi un po’ alla
volta ho iniziato a creare delle classi ClientConnectionCenter e
ServerConnectionCenter che hanno delle funzioni che mandano alcuni parametri
prima di passare la connessione al thread che la richiede che rendono trasparente l’invio di
connessioni di tipo diverso sulla porta 80. Dall’altro lato ho dovuto parallelamente creare le
classi ClientConnectionHandler e ServerConnectionHandler dedicate
unicamente a raccogliere le connessioni e a passarle alle classi
ClientConnectionDeliver e ServerConnectionDeliver. Queste ultime due
fanno il parsing delle connessioni ricevute e in base ai parametri iniziali stabiliscono a quale
thread smistare la connessione. In questo modo, avendo creato un vero e proprio protocollo
di comunicazione, è possibile mandare, ricevere smistare connessioni di tipo diverso tutte
sulla stessa porta.
Poiché spesso ci si trova in una rete chiusa allora ho supposto l’utilizzo di un server proxy di
appoggio, http, socks 4 o 5. Per rendere possibile questo ho creato una classe Connection
che implementa le stesse funzioni di una Socket, ma, una volta instaurata la connessione,
rende possibile l’utilizzo di essa come fosse una normale Socket a prescindere che la
connessione sia avvenuta a livello inferiore in modo diretto oppure tramite proxy.
Quando poi ho voluto testare la mia applicazione via Internet, poiché io ho Fastweb, la cui
rete ha un IP Privato, allora mi sono reso conto che io potevo inviare i messaggi ma non
potevo riceverli. Allora ho pensato di introdurre la possibilità di un’altra modalità di
collegamento: dato che si mantiene una connessione stabile tra Client e Server, la
mainConnection, aperta per tutta la durata del collegamento, ho pensato di mettere in
ascolto il Client su questa connessione. Quando il Server ha bisogno di contattare il Client,
perché qualche altro Client lo vuole contattare, allora invece di tentare invano di aprire una
Socket sulla porta 80 manda al Client la richiesta di creare una nuova connessione verso il
Chat HELP DESK su HTTP
71
Server sulla mainConnection. Ciò è sempre possibile poiché il Client è all’interno della
rete con IP Privato. Una volta ricevuta la connessione il Server la può utilizzare come vuole,
infatti una Socket una volta creata non è altro che un “canale” da cui inviare e ricevere dati:
non c’è differenza se l’ha creata il Client o il Server.
Utilizzando la lavagna mi sono reso conto che le linee su essa disegnata scomparivano
quando riducevo a icona o semplicemente se la lavagna veniva coperta, anche parzialmente,
da un’altra finestra. Allora ho deciso di far memorizzare in dei vettori, boardLines, tutte
le linee disegnate o ricevute, per ogni lavagna. Ogni volta che la lavagna viene visualizzata
viene chiamato automaticamente il metodo public void
paintComponent(Graphics gIBP) della classe ImageBoard, che ridisegna tutte
le linee che erano state fatte in precedenza. Quando la lavagna viene cancellata il vettore
delle linee viene svuotato.
Una volta attaccato un BufferedReader oppure un InputStreamReader il
JavaRuntimeSystem crea un buffer di sistema in cui i dati in arrivo vengono memorizzati per
velocizzare le operazioni di lettura. Quest’operazione automatica mi ha provocato un grande
disagio: i dati provenienti dal Server e destinati al Client e viceversa, hanno all’inizio un
codice che dovrebbe essere letto con le readLine, per far capire ai
ConnetionDeliverThread dove smistare la connessione, seguito dai dati veri e propri
del messaggio. Il problema si pone quando i thread destinatari sono thread che devono
trasmettere slides o files perché è necessario che i dati siano trattati in formato grezzo, cioè a
livello di bytes. Inizialmente avevo tentato di leggere i dati direttamente
dall’inputstream con una normale read ma stranamente, ogni tanto e non sempre,
alcuni dati andavano persi e i files arrivavano danneggiati. Inizialmente credevo fosse un
problema di sincronizzazione tra thread ma alla fine mi sono reso conto che i dati mancanti
dal files trasmesso potevano essere successivamente letti dal Reader che era stato creato
dal ConnetionDeliverThread per fare il parsing del tipo di connessione. Tuttavia
questi dati potevano essere letti solo con delle readLine in formato testo e quindi alcuni
byte perdevano significato! Non sono riuscito a trovare nessuna funzione Java predefinita
che mi permetteva di far il “flush” del buffer di sistema. Sorgeva un altro problema: una
volta chiuso il bufferedReader oppure l’InputStreamReader automaticamente
viene definitivamente chiuso il Socket diventando quindi inutilizzabile per il
messagePrcessorThread e lo slidePrcessorThread. A questo punto l’unica
soluzione che mi è venuta in mente è stata quella di reinventare la funzione predefinita Java
Chat HELP DESK su HTTP
72
di readLine, ma rendendola applicabile direttamente sull’inputStream di dati grezzi,
quindi senza buffer. Tale funzione è contenuta nei ConnetionDeliver e nelle classi
dedicate alla gestione dei files e delle slides del Server e del Client.
Chat HELP DESK su HTTP
73
99 CCOONNCCLLUUSSIIOONNII
9.1.1 STATISTICHE DEL PROGETTO Linee di codice package RaiayClientHelpDesk 4734
Linee di codice package RaiayServerHelpDesk 3041
Linee di codice package Gui (Client) 2166
Linee di codice package Gui (Server) 70
Linee di codice package Net (Client e Server) 920
Linee di codice package Exception (Client e Server) 129
Linee di codice package Audioplayer (Client) 246
Linee di codice package FileChooser (Client) 222
Linee di codice package ProgressMonitor (Client) 328
Totale linee di codice del Client 8745
Totale linee di codice del Server 4160
Classi del Client 42+5
Classi del Server 24
Dimensione del Client 4.09 Mb
Dimensione del Server 0.3 Mb
Dimensione Documentazione Api 1.69 Mb
Dimensione Class Diagram 16 Mb
Dimensione di Questo Documento 735 Kb
Classi totali del progetto 71
Linee di codice totali del progetto (LOC) 12905
Dimensione totale del progetto (compreso di tutta la
documentazione) 22.7 Mb
9.1.2 RINGRAZIAMENTI Per primi vorrei ringraziare i miei genitori che mi hanno mantenuto agli studi durante questi
anni di corso.
Vorrei ringraziare anche i miei amici, i miei parenti e la mia ragazza che mi hanno
incoraggiato e sostenuto nei momenti più difficili.
Chat HELP DESK su HTTP
74
Vorrei ringraziare anche tutti professori, soprattutto quelli che si sono resi disponibili, e i
tutors che mi hanno insegnato le nozioni necessarie per portarmi a preparare questo
materiale.
Un ringraziamento particolare va al prof. Vialetti che si è reso disponibile a seguirmi durante
la realizzazione della mia tesi.
9.1.3 BIBLIOGRAFIA Alcune immagini e informazioni sono state reperite da vari siti Internet e documenti trovati
grazie al famosissimo motore di ricerca Google.