FACOLT DI INGEGNERIA - raiday.com Triennale/Tesi di Laurea.pdf · FACOLTÀ DI INGEGNERIA Tesi di...

74
Chat HELP DESK su HTTP 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

Transcript of FACOLT DI INGEGNERIA - raiday.com Triennale/Tesi di Laurea.pdf · FACOLTÀ DI INGEGNERIA Tesi di...

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

2

a mio Padre e mia Madre

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

34

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.