PROGETTO E SVILUPPO DI UN SOFTWARE IN “JAVA” PER LA

annuncio pubblicitario

UNIVERSITÀ
POLITECNICA
DELLE
MARCHE
FACOLTÀ
DI
INGEGNERIA
Corso
di
Laurea
in
Ingegneria
Informatica
e
dell’Automazione
PROGETTO
E
SVILUPPO
DI
UN
SOFTWARE
IN
“JAVA”
PER
LA
TELEREFERTAZIONE:
SEZIONE
CARTELLA
CLINICA
Laureando:
Giovanni Belelli
Relatore:
Prof. Aldo Franco Dragoni
Correlatore:
Prof. Paolo Puliti
Anno
Accademico
2007/2008
INDICE
INTRODUZIONE............................................................................... 1
CAPITOLO 1 - LA TELEMEDICINA................................................. 2
1.1 TIPI DI TELEMEDICINA ................................................................................... 3
1.2 OBIETTIVI .................................................................................................... 4
1.3 VANTAGGI ................................................................................................... 5
1.4 SVANTAGGI E PROBLEMI ............................................................................... 6
1.5 APPLICAZIONI .............................................................................................. 7
1.6 LA TELEMEDICINA IN ITALIA ........................................................................... 8
CAPITOLO 2 - IL PROGETTO “MEDTEL”.................................... 10
2.1 FINALITÀ .................................................................................................. 11
2.2 FIGURE PARTECIPANTI............................................................................... 11
2.3 SOLUZIONI TECNICHE ADOTTATE ................................................................ 17
CAPITOLO 3 - LA CARTELLA CLINICA....................................... 22
3.1 COM’È COSTITUITA .................................................................................... 23
3.2 IL PROFILO DEL PAZIENTE .......................................................................... 24
3.3 L’ANAMNESI .............................................................................................. 25
3.4 PROBLEMI CLINICI DEL PAZIENTE ................................................................ 29
CAPITOLO 4 - GOOGLE WEB TOOLKIT ..................................... 33
4.1 CARATTERISTICHE .................................................................................... 35
4.2 ARCHITETTURA ......................................................................................... 40
4.3 LATO CLIENT E LATO SERVER ..................................................................... 41
I
CAPITOLO 5 - SOLUZIONI TECNICHE CARTELLA CLINICA .... 51
5.1 COM’È FATTA ............................................................................................ 51
5.2 CLINICALFOLDER ....................................................................................... 55
5.3 PATIENT PROFILE ...................................................................................... 62
5.4 ANAMNESIS ............................................................................................... 69
5.5 ALLERGOLOGY .......................................................................................... 71
5.6 FAMILIARS ................................................................................................. 75
5.7 FAMILY PATHOLOGIES ................................................................................ 80
5.8 PATHOLOGICALS ........................................................................................ 87
5.9 PHYSIOLOGICALS ....................................................................................... 92
5.10 PATIENT CLINICAL PROBLEM .................................................................... 95
CAPITOLO 6 - CONCLUSIONI .................................................... 100
6.1 OBIETTIVI RAGGIUNTI .............................................................................. 100
6.2 PROBLEMI RISCONTRATI .......................................................................... 101
6.3 MIGLIORAMENTI POSSIBILI ....................................................................... 102
6.4 CONFRONTI CON ALTRE TECNOLOGIE ....................................................... 104
6.5 CONFRONTO CON “MIRO ON RAILS”......................................................... 107
6.6 CONSIDERAZIONI FINALI SUL TIROCINIO ..................................................... 110
APPENDICE – CODICE SORGENTE .......................................... 112
CLINICAL FOLDER – LATO CLIENT.................................................................... 112
CLINICAL FOLDER – LATO SERVER ................................................................. 134
ALLERGOLOGY – LATO CLIENT ....................................................................... 135
ALLERGOLOGY – LATO SERVER ...................................................................... 140
BIBLIOGRAFIA ............................................................................ 144
II
INTRODUZIONE
Le tematiche affrontate da questa tesi riguardano la telerefertazione
e la telemedicina in generale. L’utilizzo del Java tramite la tecnologia
Google Web Toolkit ha permesso di creare un’ampia e flessibile
applicazione software atta a svolgere tali compiti. Lo sviluppo è stato
effettuato in collaborazione con l’azienda sanitaria locale, che ha fornito
supporto dal punto di vista medico, mentre la parte realizzativa è stata
curata da un gruppo di cinque tirocinanti, tra cui il sottoscritto. Nel
seguito dei capitoli verrà dapprima presentato il concetto di
telemedicina e successivamente si entrerà nel dettaglio del progetto.
Nello specifico verrà trattata la sezione riguardante i dati medici del
paziente, nonché tutte le altre informazioni presenti nella cartella
clinica.
Un capito a parte sarà lasciato per descrivere le tecnologie utilizzate
e soprattutto verrà fornita una dettagliata descrizione del Google Web
Toolkit, in modo da spiegarne i meccanismi di funzionamento.
In conclusione sarà fornita una panoramica sugli obiettivi raggiunti,
le eventuali migliorie possibili da applicare al software creato ed un
confronto con altre tecnologie più conosciute.
1
CAPITOLO 1 - LA TELEMEDICINA
La telemedicina ha molte e differenti definizioni. La definizione
ufficiale secondo la Commissione Europea è la seguente: la
telemedicina è l’integrazione, monitoraggio e gestione dei pazienti,
nonché l’educazione dei pazienti e del personale, usando sistemi che
consentono un pronto accesso alla consulenza di esperti ed alle
informazioni del paziente, indipendentemente da dove il paziente o le
informazioni risiedono.
Naturalmente la telemedicina è utilizzata quando la distanza è un
fattore critico che influisce nella risoluzione ottimale del rapporto
medico/paziente e perciò viene necessario l’utilizzo di tecnologie
dell’informazione e della comunicazione per lo scambio di informazioni
rilevanti per la diagnosi e più in generale per il monitoraggio e la
gestione dei pazienti.
Un fattore interessante della telemedicina è anche quello
riguardante i costi della stessa. Pur permettendo assistenza sanitaria a
grande distanza, i costi di tali servizi sono contenuti: questo soprattutto
nel caso di zone dove l’assistenza sanitaria è offerta a zone dove la
prestazione medica non è disponibile.
La telemedicina permette anche la formazione professionale di
medici ed infermieri, fondendo anche le varie esperienze accumulate nei
vari progetti, così da poter migliorare la qualità dei servizi: un medico
può specializzare altri medici che richiedono una seconda opinione su
un caso clinico.
2
Capitolo
1
–
La
Telemedicina
L’utilizzo della telemedicina si presta bene tra i paesi dotati di
maggiori tecnologie e i paesi in via di sviluppo, attuando anche una
crescita tecnologica in quest’ultimi.
1.1 Tipi di telemedicina
Ci sono due differenti tipologie di applicazione della telemedicina:
“real time” (sincrona) e “store-and-forward” (asincrona).
La telemedicina in real time può essere intesa semplicemente come
l’utilizzo del telefono come mezzo di comunicazione o in maniera più
complessa con l’utilizzo di robot da chirurgia. Naturalmente è
necessaria la presenza di entrambe le parti, medico e paziente, nello
stesso istante di tempo e il mezzo di comunicazione deve permettere
una trasmissioni di dati in real time, per evitare complicazioni dovute a
ritardi. La più utilizzata tecnica di telemedicina sincrona è quella
mediante degli strumenti di video conferenza utilizzati per la
telerefertazione.
La telemedicina asincrona, invece, si basa sull’acquisizione dei dati
medici, come radiografie digitali e simili, per poi trasmetterli al medico
specialista che li valuterà successivamente. Non è richiesta la presenza
delle parti nello stesso istante in quanto il dato è salvato su una struttura
e quindi recuperabile in qualunque momento. In questa tesi verrà trattata
questo tipo di telemedicina in quanto si adatta meglio alle esigenze e
non necessita di particolari e specifiche attrezzature. Il funzionamento e
la gestione dei dati sarà presentata nel capitolo successivo.
3
Capitolo
1
–
La
Telemedicina
1.2 Obiettivi
Gli obiettivi della telemedicina sono quelli di poter fornire un
adeguato servizio sanitario a chi, per un problema di distanza o per altri
tipi di problemi, non può ottenere una prestazione sanitaria direttamente.
Naturalmente questa non deve essere una condizione necessaria, ma
solamente sufficiente, in quanto la telemedicina, come sopra citato, può
essere finalizzata anche alla formazione professionale o anche
solamente come metodo di confronto e accumulo di esperienze tra i vari
Paesi nel mondo: il servizio offerto deve risultare e risulterà sicuramente
migliore.
La telemedicina quindi propone il suo maggiore utilizzo soprattutto
per i paesi in via di sviluppo, come i paesi africani, nei quali le
prestazioni mediche spesso non sono possibili o per mancanza di
personale o per l’elevato costo. Le diagnosi vengono quindi trattate e i
pazienti gestiti da strutture idonee, come possono essere ospedali o
missioni umanitarie presenti sul posto.
Si creano quindi le possibilità per un sensibile miglioramento della
vita dei pazienti, permettendo di curarsi a domicilio o nelle vicinanze,
senza quindi venire a creare problemi di alcun genere. Per il paziente è
sempre possibile avere a disposizione degli specialisti che ovviamente
accrescono la qualità delle decisioni mediche prese: il servizio che si
vuole fornire è di elevata qualità.
La tempestività e rapidità del sevizio ricopre un ruolo importante in
questo campo, in quanto, si deve garantire la più possibile e tempestiva
assistenza, soprattutto per la gestione di casi di urgenza.
4
Capitolo
1
–
La
Telemedicina
L’obiettivo finale è quindi permettere a tutti di avere la possibilità
di essere diagnosticati con lo stesso grado di affidabilità, e quindi
sicurezza medica, in tutte le parti del mondo, anche senza essere
direttamente a contatto con il medico, ovviamente avendo un occhio di
riguardo per i paesi più bisognosi quali gli stati dell’Africa e tutti i paesi
in via di sviluppo.
1.3 Vantaggi
Con l’avvento e la diffusione delle tecnologie informatiche e di
nuovi canali di comunicazione, come ad esempio internet, è stato
possibile diffondere la telemedicina anche a grande distanza,
introducendo vantaggi sia per il paziente che per lo stesso personale
medico.
La nascita della telemedicina permette infatti cure più rapide e
minor spostamento di risorse, sia mediche che dei pazienti stessi, senza
tralasciare che le comunicazioni e quindi gli aggiornamenti dei dati del
paziente sono senza dubbio più veloci. Il tutto provoca un sensibile
miglioramento sia della qualità dei servizi per il cittadino, che è più
tutelato, sia delle condizioni di lavoro del personale medico, che può
accedere e gestire più velocemente le informazioni.
I tempi di ricovero, ma soprattutto la transizione casa-medicoospedale è sensibilmente ridotta, perché ovviamente il tutto avviene per
vie telematiche e si evita anche molta burocrazia.
Per casi particolari, come le calamità naturali o per temporanei
aumenti di popolazione cui necessita una cura, l’utilizzo della
5
Capitolo
1
–
La
Telemedicina
telemedicina si adatta perfettamente in quanto la sua struttura è molto
flessibile.
Inoltre con una ben strutturazione del sistema di gestione dati e
organizzando al meglio il sistema sanitario si possono snellire le varie
procedure e quindi contenere la spesa sanitaria, avendo perciò un
riscontro economico positivo.
Un altro vantaggio, che non ha riscontri nel concreto, ma che mi
piace citare, è che con l’utilizzo della telemedicina si possono aiutare e
salvare molte vite di persone meno fortunate, che non riescono ad avere
una prestazione medica o se ce l’hanno è poco affidabile, il tutto anche
solo stando comodamente nel proprio Paese ed avendo le migliori
attrezzature a disposizione.
1.4 Svantaggi e problemi
Un problema in passato è stato senza dubbio l’elevato costo delle
attrezzature
mediche
e
delle
tecnologie
utilizzate
per
la
telecomunicazione. Anche lo stesso utilizzo di computer può essere un
fattore negativo: il costo può risultare elevato, ma anche lo stesso
utilizzo può risultare di difficile comprensione.
Tuttavia questo
problema è stato in parte risolto grazie all’abbassamento dei costi e ad
una formazione informatica più diffusa: si cerca di diffondere metodi
che favoriscano la comprensione delle tecnologie utilizzate in
telemedicina.
Anche l’utilizzo di formati di codifica e decodifica dei dati
trasmessi non sono ancora standardizzati e quindi le apparecchiature
possono avere problemi di compatibilità. La soluzione è puramente di
6
Capitolo
1
–
La
Telemedicina
carattere burocratico, cioè basterebbe “mettersi d’accordo” su quale
formato debba essere utilizzato: tale scelta dovrebbe essere duratura nel
tempo così da poter uniformare il sistema.
Un altro svantaggio è quello di dover sensibilmente cambiare i
metodi tradizionali di lavoro. L’introduzione della telemedicina
comporta infatti un cambio totale di mentalità, che a volte può
provocare dei rifiuti verso la stessa. Anche il fatto di utilizzare internet
per poter diagnosticare un paziente è una procedura che molti medici
possono ritenere poco consona. In questo caso però, grazie alla dovuta
formazione e alla presa di coscienza di questa nuova realtà, anche
questo problema può essere superato agevolmente.
1.5 Applicazioni
I campi in cui la telemedicina è utilizzata sono svariati e sono in
continuo evoluzione e diffusione. La telepatologia, che è una branca
della telemedicina, prevede infatti il trasferimento di immagini digitali
macroscopiche e microscopiche a scopo diagnostico o educativo. In
cardiologia è utilizzata per trasmettere i tracciati elettocardiografici, in
radiologia invece vengono digitalizzate e trasmesse le radiografie, in
dermatologia vengono trasferite foto digitali delle ferite cutanee, per la
ginecologia vengono monitorate le gravidanze e via dicendo; ogni
branca della medicina può utilizzare questa tecnologia per migliorare
l’esercizio delle proprie attività sia cliniche che di formazione
professionale.
Oltre all’invio di dati la telemedicina prevede anche il
mantenimento di dati quali il gruppo sanguigno, la pressione sanguigna
7
Capitolo
1
–
La
Telemedicina
e una anamnesi totale del paziente: tali dati essendo in formato digitale
sono semplici da reperire ed eventualmente da modificare.
1.6 La telemedicina in Italia
In Italia la telemedicina è nata a partire dal 1976, con la
trasmissione di elettrocardiogrammi a distanza. Con l’avvento del 118,
per la gestione delle urgenze la telemedicina ha avuto un più ampio
utilizzo: nel 1992 l’Italia era il primo paese nella Comunità Europea con
il numero maggiore di sperimentazioni sul campo.
Iniziative importanti sono stati il collegamento telematico
dell’ospedale San Raffaele di Milano con l’ospedale di Sarajevo, il
progetto che collega Napoli alle isole di Ischia e Procida e ancora molti
altri progetti pilota presenti tra gli istituti di cura e le aziende locali.
Nel 2002-2004 si è attuato un piano sanitario proprio propenso a
promuovere la telemedicina e a valorizzarla. Si cerca quindi di
diffondere la telemedicina al fine di collegare le iniziative periferiche
sotto una gestione integrata dei servizi disponibili. Lo stesso sta
avvenendo negli altri Paesi dell’Unione Europea.
Anche nelle varie università italiane sono stati istituiti dei master,
finalizzati alla teledidattica in medicina.
Sempre nel 2002 è stato fatto uno studio sull’utilizzo di un
“ospedale virtuale per l’assistenza sanitaria italiana all’estero”, che
punta ad utilizzare i servizi offerti dalla telemedicina a favore di
ospedali, centri italiani e di volontariato all’estero. Un altro progetto
avviato nel 2002 è il progetto IPOCM (Integrazione e Promozione degli
8
Capitolo
1
–
La
Telemedicina
Ospedali Italiani e dei Centri di cura con assistenza italiana nel mondo)
molto simile al precedente citato e promosso sempre dal Ministero della
Salute.
9
CAPITOLO 2 - IL PROGETTO “MEDTEL”
In
questo
capitolo
sarà
presentato
il
progetto
“MedTel”
(Medical Telereporting System), un sistema per la telemedicina
progettato in collaborazione con la ASUR di Ancona e l’Università
Politecnica delle Marche.
Grazie alle continue innovazioni nel campo dell’ampiezza di banda
e nella diffusione nel mondo, abbiamo scelto internet come mezzo di
comunicazione su cui basare il nostro progetto: internet sarà, se non lo è
già, il mezzo del futuro in cui sarà possibile svolgere tutte quelle azioni
che prima venivano svolte tramite uffici e via dicendo. Per questo
motivo un progetto che sfrutta tale mezzo di comunicazione è destinato
a durare nel tempo e a diffondersi, come noi vogliamo, sempre di più.
MedTel infatti è un portale su internet che permette la
telerefertazione, creato con lo scopo di essere utilizzato da chiunque ne
abbia bisogno e in qualunque luogo esso sia, con bisogno solo di un
personal computer e di una semplice connessione a internet.
Per prima cosa abbiamo analizzato “a chi” fosse indirizzato tale
software: come sopra citato tale strumento può essere utilizzato da tutti,
ma come scelta di base è stata presa quella di basarsi su popolazioni e
comunità africane.
Quindi abbiamo dovuto analizzare “cosa” veniva richiesto e solo
successivamente “come” doveva essere concepito: il software creato
doveva avere una completa flessibilità ed anche essere di semplice
utilizzo. Non doveva comunque essere trascurata l’affidabilità e la
sicurezza in quanto le informazioni trattate sono molto sensibili.
10
Capitolo
2
–
Il
progetto
MedTel
Come idea ci siamo basati su Miro, un progetto già cominciato
sempre nato tra la collaborazione della ASUR di Ancona e l’Università
Politecninca delle Marche.
2.1 Finalità
L’obiettivo del nostro progetto è quello di fornire all’azienda
sanitaria di Ancona un prodotto flessibile, compatto, portabile e di facile
utilizzo da chiunque in futuro ne voglia approfittare. Il prodotto creato
fornisce un servizio asincrono in grado di superare qualunque soglia
spaziale in quanto è diffuso tramite internet.
La sicurezza e l’affidabilità doveva essere comunque garantita
perché i dati trattati sono sensibilmente importanti. Si è deciso infatti di
dotare il portale di un accesso limitato e controllato solamente
dall’amministratore, per assicurare appunto che informazioni sensibili
vengano a contatto solo con le persone corrette.
MedTel punta ad essere un software di telemedicina il più completo
possibile: mira a gestire tutto il processo di telerefertazione, ma anche
tutto il processo di teleconsulto, in quanto entrambi fondamentali.
2.2 Figure partecipanti
L’architettura ideale è costituita essenzialmente da due “figure”
partecipanti quali il requester, che non è nient’altro che colui che
richiede la refertazione, ed il dottore, che invece è colui che effettua
fornisce la diagnosi.
11
Capitolo
2
–
Il
progetto
MedTel
In mezzo a queste due figure vi è una terza entità che è il luogo
dove i dati vengono memorizzati. Tale entità ha riscontro grafico nella
la cartella clinica. Infatti la cartella clinica svolge un ruolo centrale
nell’ambito della comunicazione dottore-requester perché contiene tutti
i dati del paziente sotto esame. L’archiviazione viene effettuata
ovviamente in un database, dal quale la cartella clinica preleverà i dati
riguardanti e necessari per quel paziente: ovviamente saranno presenti
varie informazioni aggiuntive riguardante l’esame quali la data ecc. La
cartella clinica verrà presa in esame nel capito successivo.
Il funzionamento del portale si basa sul concetto di evento. Questo
punto è molto importante nella concezione dell’intero progetto. Un
evento è la “formalizzazione informatica” di un problema clinico. Con
tale definizione voglio intendere la digitalizzazione per esempio di uno
o più esami di laboratorio e la conseguente archiviazione.
2.2.1 Dottore
Il dottore è un dei tre attori presenti nel sistema. Esso rappresenta i
medici o meglio ancora il personale specializzato che fornirà la diagnosi
o una seconda opinione sul paziente.
La figura del dottore entra in gioco quando viene aperto un evento e
quindi il requester richiede la refertazione: ovviamente ogni medico
avrà una o più specializzazioni e quindi sarà interessato ai soli pazienti
che rientrano in queste.
L’accesso del dottore è effettuato, come del resto per tutte le altre
figure presenti nel sistema, tramite un web browser qualunque e
l’opportuna autenticazione nel portale. La porzione di software che da
12
Capitolo
2
–
Il
progetto
MedTel
qui il dottore è in grado di utilizzare è composta da interfacce utenti
semplici e create appositamente per essere utilizzate nella maniera più
intuitiva possibile: sono state concepite per essere utilizzate anche senza
nessuna conoscenza informatica rilevante. La schermata iniziale
comprende una guida su cosa il dottore può fare e su come farlo e una
pagina con tutti gli eventi su cui il dottore può refertare. Quando il
dottore accede a tale evento ovviamente compare anche la cartella
clinica del paziente con tutti i suoi dati, dal profilo all’anamnesi fino ai
vari problemi clinici riscontrati: è ovviamente stata implementata anche
la possibilità di poter scaricare il dato ottenuto dall’esame di laboratorio.
Il dottore può anche dare una seconda opinione, se richiesta,
riguardo un problema clinico. È stata aggiunta inoltre la possibilità di
leggere anche i referti degli altri medici. Con tale meccanismo si
effettua uno scambio ancora maggiore di informazioni, si aumenta la
qualità del servizio e si effettua anche formazione medica.
2.2.2 Requester
Il requester è la figura del sistema MedTel che rappresenta qualsiasi
struttura che necessita la refertazione di un esame: può essere sia un
laboratorio di analisi, sia un ospedale nonché un privato cittadino con
necessarie conoscenze cliniche. Il termine requester infatti è stato
opportunamente utilizzato per definire un ente “richiedente”, di
qualsiasi tipologia, che voglia farsi refertare un esame.
La figura del requester è anche quella che genera gli eventi. Dopo
aver effettuato l’esame, deve provvedere alla digitalizzazione e
all’inserimento dello stesso evento nel sistema. Come per il dottore, il
13
Capitolo
2
–
Il
progetto
MedTel
requester accede tramite un web browser al portale MedTel, si autentica
e successivamente ha di fronte un’interfaccia simile a quella del dottore.
Sara presente inizialmente una descrizione delle azioni che il requester
può compiere, come l’inserimento di nuovi pazienti o la gestione di
quelli esistenti. Inoltre avrà la solita schermata di ricapitolazione dei
problemi clinici inseriti.
Attenzione a non confondere la presenza di un paziente con un
problema clinico: non è detto che un paziente presente nel sistema
debba necessariamente avere un problema clinico, può essere ancora in
fase di aggiornamento, in quanto il sistema è asincrono e non real time.
Delle organizzazioni potrebbero anche solo mantenere un elenco di tutti
i pazienti, senza necessariamente avere dei problemi da refertare, per la
semplice volontà di avere un elenco informatico compatto e di rapida
consultazione. Infatti oltre ai problemi da refertare, il requester deve
inserire anche i dati che il paziente come ad esempio le informazioni
sull’anamnesi.
Ritornando alla generazione dell’evento, una volta effettuata, viene
scritto il dato con le varie informazioni nel database centrale. Da qui il
requester attende la refertazione o osserva le varie refertazioni finché
non si potrà ritenere soddisfatto. Sono quattro le fasi della refertazione
che il requester monitorizza, anche se non è detto che debbano
necessariamente essere tutte svolte: la generazione dell’evento e lo stato
dello stesso impostato a “open”; la refertazione da parte del dottore e lo
stato impostato a “reported”; la volontà del requester di avere una
successiva refertazione con il conseguente stato impostato a “request
another”; e la chiusura del report nel quale il requester si ritiene
soddisfatto della refertazione ottenuta, con stato impostato a “close”.
14
Capitolo
2
–
Il
progetto
MedTel
2.2.3 Struttura Dati
La struttura dati è dove vengono memorizzati tutti i dati inseriti dal
requester e quindi prelevati dal dottore. Questa struttura non è
nient’altro che un database relazionale costituito da tabelle che
contengono le informazioni, divise per argomenti.
Passiamo ora ad analizzare le tabelle contenute nel database, che
come già detto sono relazionate tra loro. Infatti ogni tabella è legata ad
un’altra tabella tramite chiave esterna, che permette di rendere il tutto
più flessibile e dinamico in caso di aggiornamento e manutenzione.
Questo avviene soprattutto nelle tabelle che rispecchiano elenchi di
nomi selezionabili nella cartella clinica. Si pensi al caso della tabella
contenente le informazioni sulle allergie: i nomi delle varie allergie sono
contenute in una tabella separata rispetto a quelle delle allergie di quel
determinato paziente, così facendo quando si dovrà inserire una nuova
allergia o modificarne una vecchia, non si dovrà correggere il codice
sorgente della pagina web in questione, ma solamente modificare una
campo del database.
La gestione dei referti effettuati e dei messaggi spediti è anch’essa
gestita tramite delle tabelle. Anche le informazioni relative al paziente
sono memorizzate in una tabella apposita, come del resto i dati di ogni
singolo utente registrato al progetto MedTel. Per quanto riguarda i file
scaricati nel server dai requester si è scelto di adoperare la seguente
soluzione: per ogni file scaricato, viene salvato il percorso attuale in un
record di una tabella, nel quale sarà presente oltre a tale percorso, anche
il nome del file scelto. Il download quindi avviene attraverso la lettura
di questi due campi. Come già detto sopra la visualizzazione di questi
“meta-dati” verrà resa possibile grazie alla cartella clinica. Proprio
15
Capitolo
2
–
Il
progetto
MedTel
l’importanza dei dati e delle informazioni qui presenti saranno oggetto
del capito successivo, completamente dedicato alla cartella clinica.
2.3.3 Utenti e Privilegi
In questa sezione sarà presentata l’organizzazione dei privilegi
assegnati agli utenti nel progetto MedTel. Le seguenti scelte sono state
fatte in quanto, oltre a dover differenziare dottore e requester, servivano
delle figure “collaborative”, necessarie per la gestione e manutenzione
del progetto. Ogni privilegio è gestito all’interno della struttura dati in
cui è presente una tabella utenti con questo genere di informazioni: un
campo ne contraddistingue il “tipo” di utente.
Due tipologie di utenti, come si potrà ben capire, non sono
nient’altro che le due figure sopra citate, cioè il dottore ed il requester.
Questi sono differenziati a livello di database e ovviamente l’accesso
consente differenti visualizzazioni e interfacce.
Oltre a queste due tipologie di utenti ne sono state create altre due,
necessarie per l’amministrazione. La prima presa in esame è il
super-amministratore, cioè colui che ha tutti i privilegi sul database: il
suo compito non sarà quello di creare dottori o requester, ma di creare i
manager. È prevista anche la cancellazione e quindi il riassegnamento a
qualche altro manager degli utenti creati. I manager, che è appunto la
seconda tipologia creata, sono coloro che hanno il compito di creare i
dottori e i requester, ma sono impossibilitati a creare altri manager. Tale
figura è anche responsabile della cancellazione di dottori e requester ed
in questo ultimo caso, anche alla riassegnazione dei pazienti gestiti.
16
Capitolo
2
–
Il
progetto
MedTel
Tale gerarchia a piramide, ci è sembrata la più solida e la più
flessibile di fronte ad una possibile espansione, in quanto il lavoro è
suddiviso per gradi e con il meccanismo di rassegnazione non vi è
possibilità di perdere parzialmente dati o peggio ancora pazienti.
2.3 Soluzioni tecniche adottate
In questa sezione introdurrò le soluzioni tecniche che abbiamo
utilizzato per svolgere il progetto. Innanzitutto ricordo che avevamo
bisogno di costruire un prodotto innovativo e flessibile, ma anche molto
user-friendly, in quanto diretto ad un pubblico non necessariamente
preparato dal punto di vista informatico. Serviva costruire il portale
utilizzando delle soluzioni che fossero sia complete e funzionali, ma
senza trascurare la “leggibilità” del software creato: vorrei precisare che
il progetto oltre che essere pienamente funzionale dal punto di vista
informatico, doveva quindi esserlo, con la stessa importanza,
graficamente. Inoltre dovevano essere utilizzati ovviamente prodotti
open source.
Ci siamo dovuti immedesimare in coloro che avrebbero dovuto
utilizzare questo software e capire quali soluzioni potessero andare
meglio.
Per il server, la scelta è ricaduta su Kubuntu Server, che offre
affidabilità e sicurezza, senza tralasciare le prestazioni e la stabilità.
Tale server ovviamente è stato collocato presso un laboratorio del
D.E.I.T. al polo di Ingegneria.
17
Capitolo
2
–
Il
progetto
MedTel
Apache Tomcat
Il web server utilizzato invece è stato Apache Tomcat 6.0. Si tratta
di un prodotto con licenza Apache, cioè con la possibilità di utilizzo
anche per progetti non open source e senza l’obbligo di rilascio dei
sorgenti modificati: è una licenza per software libero.
Si discuteranno ora brevemente alcune delle caratteristiche
principali di questo web server. Innanzitutto il nostro progetto, che è
un’applicazione web, ha bisogno di uno schema gerarchico prestabilito
di file e directory. Tutto questo in Tomcat avviene attraverso la
directory radice /webapp. Questa directory rappresenta il context path
dei servlet che si creeranno. Tale directory conterrà tutti gli elementi che
compongono le applicazioni web e quindi sarà il luogo in cui metteremo
anche il nostro progetto: in questa directory o nelle eventuali
sottodirectory quindi andranno messi i file e le directory come per un
sito web statico.
Per la directory /webapp o le eventuali sottodirectory contenenti
l’applicazione web andranno comunque presi degli accorgimenti
particolari e sarà necessario la creazioni di altre directory particolari.
All’interno della directory root della nostra applicazione si troverà una
directory speciale, chiamata WEB-INF. In questa directory sono
presenti i file o directory riservati, come quelli di configurazione.
Uno dei file contenuti in questa cartella è il file web.xml. Questo
file è il descrittore della nostra applicazione web e contiene la
configurazione necessaria per il funzionamento dei servlet: vengono
definiti gli alias e mappati i percorsi dei servlet.
Sempre all’interno della cartella WEB-INF sono contenute le
directory classes e lib. La prima contiene le classi java compilate, la
18
Capitolo
2
–
Il
progetto
MedTel
seconda invece è destinata a contenere gli archivi Jar necessari per il
funzionamento dell’applicazione web (librerie esterne). Nel nostro caso
particolare, siamo un po’ usciti da questa regola, in quanto il deploy
module automatico di Eclipse invece di copiare le classi compilate nella
directory classes, crea un archivio Jar e lo posiziona nella cartella lib,
insieme a quelle esterne.
Passiamo ora ad elencare come si effettua il deployment
dell’applicazione web stessa in Tomcat. L’applicazione web creata
viene compressa in un archivio WAR (Web Application Archive),
molto simile ad un pacchetto Jar. Questi archivi hanno la funzione di
contenere tutta l’applicazione in un unico archivio, ma anche di rendere
operativa l’applicazione web: infatti, in pratica, basta copiare il suddetto
file WAR nella cartella /webapp di Tomcat e lo stesso web server
provvederà allo “scompattamento” in una directory con lo stesso nome
del file WAR.
La struttura dati e le interfacce
La struttura dati è stata implementata su un database MySQL, in
quanto è in primis un prodotto open source, è veloce ed infine è
semplice nel suo utilizzo. La compatibilità è un altro punto molto
importante: MySQL è compatibile sia con i sistemi basati su Unix che
su MS Windows. Verrà ora presentato un elenco di tutte le tabelle
presenti nel database, con una sommaria decrizione di esse.
19
Capitolo
2
–
Il
progetto
MedTel
Ecco l’elenco delle tabelle:
• Allergies: elenco delle allergie che è possibile attribuire ad un
paziente;
• Allergy_categories: le categorie in cui le allergie sono
suddivise;
• Anamnesis_allergologies: allergie di ogni relativo paziente;
• Anamnesis_familiars: informazioni relative ai genitori dei
pazienti;
• Anamnesis_family_pathologies: patologie avute dai parenti
dei pazienti;
• Anamnesis_pathologicals: informazioni sulle patologie
passate diagnosticate ai pazienti;
• Anamnesis_physiologicals: problemi fisiologici generali dei
pazienti;
• Events: informazioni sugli eventi;
• Exams: elenco degli esami memorizzabili;
• Exams_files: mappatura dei file degli esami di laboratorio;
• Exams_users: relazione tra utente ed evento associato;
• Pathologies: elenco delle patologie memorizzabili;
• Patients: tutti i dati di carattere generico (non medico) dei
pazienti;
• Reports: informazioni riguardo ai referti e ai messaggi;
• Users: informazioni sugli utenti registrati, tra cui i privilegi;
• Visits: dati memorizzati riguardanti i problemi clinici, non
relativi all’anamnesi;
Per la creazione vera e propria del portale, cioè per tutte quelle
iterazioni lato client e server, e per la creazione delle interfacce grafiche,
abbiamo scelto il framework open source fornito da Google: il Google
20
Capitolo
2
–
Il
progetto
MedTel
Web Toolkit (GWT). Questa soluzione è stata presa di comune accordo
con la ASUR di Ancona, in quanto rappresentava, oltre che ad una
soluzione open source, anche un nuovo modo di creare portali sul web
ed in più risolveva molto i problemi legati al creare un portale
graficamente semplice e funzionalmente intuitivo. Una dettagliata
presentazione di questo framework verrà fatta nel capitolo 4.
21
CAPITOLO 3 - LA CARTELLA CLINICA
La cartella clinica è la figura centrale del sistema MedTel. Essa
contiene tutte le informazioni relative al paziente ed in più rappresenta il
“luogo” in cui avviene lo scambio di informazioni tra dottore e
requester. Infatti la cartella clinica non è nient’altro che la soluzione
grafica di tutti i dati relativi al paziente presenti nel database centrale:
tutti gli eventi e le informazioni vengono salvate in questo database e
visualizzate tramite opportune interfacce agli utenti, siano essi
appartenenti alla categoria dottore o requester.
Una cosa importante da dire è che ovviamente la cartella clinica
sarà presentata ugualmente sia per il dottore che per il requester, con
l’unica importante differenza, che quest’ultimo è l’unico che può e deve
inserirvi e manipolare i dati all’interno: solo la figura del requester, che
è colei che gestisce il paziente, è a contatto diretto con lo stesso.
Verrà quindi prima descritta in modo generico con una panoramica
di funzioni generali, per poi passare nello specifico di ogni sezione della
cartella clinica.
Non viene in questo capitolo tuttavia menzionata nessuna delle
soluzioni tecnologiche utilizzate, in quanto la descrizione dettagliata di
queste è contenuta nel capitolo 5.
22
Capitolo
3
–
La
cartella
clinica
3.1 Comʼè costituita
La creazione della cartella clinica è un passo molto importante. Le
caratteristiche che infatti doveva avere la nostra cartella clinica sono le
seguenti: avere a disposizione i dati anamnestici e del paziente in
generale, fornire con una certa rapidità le informazioni desiderate,
essere flessibile e duratura nel tempo.
Innanzitutto bisogna dire che in ambito medico esistono due tipi di
cartelle cliniche, quelle utilizzata in medicina generale e quella
utilizzata in ambito ospedaliero. In ospedale sarà necessario focalizzare
l’attenzione sugli eventi prossimi che portano a un certo iter diagnostico
verso una determinata patologia. In medicina generale invece deve
essere utilizzata una cartella clinica orientata ai problemi, in cui tutti i
dati ruotino attorno al problema per cui è richiesta la visita. Si
distinguono quindi tra problemi attivi, cioè quei problemi che non
hanno ancora trovato soluzione, e problemi inattivi, i quali sono già stati
risolti.
La nostra cartella clinica contiene i dati di base generici del
paziente, dalle allergie ai problemi familiari; una lista dei problemi,
siano essi attivi che inattivi, utilizzati per una buona diagnosi; un “diario
clinico” del paziente che comprende i dati oggettivi, quali la pressione,
il polso e simili, e dati soggettivi, come i sintomi manifestati. Tutto
questo è corredato dalla possibilità di visualizzare un eventuale esame di
laboratorio, prima digitalizzato e memorizzato dalla struttura che
gestisce il paziente.
Un’ultima osservazione sulla costituzione della cartella clinica va
fatta riguardo alla terminologia utilizzata. Infatti nell’inserimento dei
dati sarebbe meglio utilizzare una terminologia universale, atta
23
Capitolo
3
–
La
cartella
clinica
soprattutto a non creare possibili diversità di interpretazione tra i vari
medici, cosa molto importante nel campo della telemedicina.
3.2 Il profilo del paziente
Passiamo ora ad analizzare la struttura vera e propria della cartella
clinica. Inizialmente è presente il profilo del paziente con tutti i suoi dati
anagrafici: questo profilo serve al requester per poter riconoscere il
proprio paziente in caso di gestione di una grande mole di pazienti;
inoltre serve anche al dottore per sapere con che paziente ha a che fare,
in quanto magari la provenienza potrebbe anche essere un fattore da
considerare in caso di diagnosi.
I dati presenti nel profilo sono la data di nascita e la città di nascita,
informazioni generali sulla residenza attuale, la struttura in cui è
ospitato, più altre informazioni generali quali il sesso, il grado di
istruzione, lo stato civile e la professione svolta, senza trascurare che
sono anche presenti informazioni per contattare direttamente il paziente
come il numero di telefono e l’e-mail. Inoltre è anche stata
implementata la possibilità di mantenere in archivio pazienti deceduti,
perciò come dato verrà anche fornita la data di morte. Questo è stato
fatto per il semplice motivo di avere una più ampia visione d’insieme
della situazione locale: si pensi che, per esempio, in caso di un’epidemia
sarebbe utile sapere il tempo in cui si trasmette e dopo quanto avviene
l’eventuale decesso.
I dati utili per contattare il paziente direttamente sono stati inseriti
per essere utilizzati come “rubrica” da parte del requester e far
aumentare la comunicazione e quindi la qualità del servizio offerto.
24
Capitolo
3
–
La
cartella
clinica
Ricordo inoltre che gli stessi dati sono visibili sia dal requester che dal
dottore: tali dati non dovrebbero essere utilizzati dal dottore per
contattare direttamente il paziente, tranne che per emergenza. Non
devono essere quindi utilizzati come modo per scavalcare la figura del
requester, che deve e dovrà fare da tramite tra il sistema e il paziente.
Infatti spesso il paziente non ha conoscenze mediche adatte a fornire, ne
a capire, diagnosi o altre generalità mediche. Se si sfruttassero quindi
tali dati per creare un legame diretto dottore-paziente non si rischierebbe
nient’altro che peggiorare la situazione.
3.3 Lʼanamnesi
Successivamente è presente la sezione riguardante l’anamnesi del
paziente con varie sottocategorie così dal rendere tutto più immediato
ma allo stesso tempo avere una visione completa e dettagliata di dati
relativi al paziente.
La sezione anamnesi è stata creata con l’intento di avere sempre
tutte le informazioni davanti al dottore: tutte le informazione, che
verranno sotto descritte, rimangono sempre in primo piano e sempre
quindi visibili. Ogni sottosezione è prima presentata da un riepilogo
della stessa, con un elenco delle patologie e problematiche generali;
successivamente si può anche accedere nel dettaglio di queste, avendo
informazioni sempre più specifiche. Abbiamo deciso di operare con
questo genere di struttura per dare un’ampia ma completa visuale del
paziente, cosicché al primo impatto già il dottore può avere un’idea
generale sul da farsi.
25
Capitolo
3
–
La
cartella
clinica
Le sezioni di seguito sono identiche dal punto di vista del dottore e
del requester: a questo proposito quindi bisogna ricordare che le
informazioni citate sono inserite dal requester, tramite un’apposita form
di inserimento, e recepite dal dottore. Nel formare questa sezioni ci
siamo basati sulla considerazione che è meglio fornire più informazioni
possibile, anche magari in surplus, piuttosto che fornirne meno, in
quanto questo può causare una mancata diagnosi corretta, tutto a
discapito del paziente.
Allergie
La prima sottosezione che si incontra è quella relativa alle allergie
del paziente.
La prima scheda riassuntiva fornisce informazioni sul numero di
allergie salvate nella struttura dati e relativi a quel paziente, e
naturalmente quali allergie questo paziente ha o ha avuto. Quando si
entra nel dettaglio vengono forniti informazioni in dettaglio dell’allergia
in questione: la data di inizio dell’allergia e l’eventuale data di fine se
questa non è più presente. Come ultimo, sono presenti anche delle note
generiche sull’allergia riscontrata che possano essere utili per una
migliore diagnosi o lettura stessa della cartella clinica: si è cercato di
rendere il più dettagliato possibile la rilevazione dell’allergia.
Informazioni generali sui genitori
La sottosezione successiva è quella comprendente i dati della
famiglia. Le informazioni qui presenti sono riguardanti il padre e la
madre del paziente.
26
Capitolo
3
–
La
cartella
clinica
Qui non è presente come nella scheda precedente una parte
riassuntiva, in quanto i dati sono immediati.
Dal punto di vista del dottore, qui vengono prelevate le seguenti
informazioni: viene reso noto se sono ancora vivi i genitori e qual è il
loro gruppo sanguigno.
Naturalmente anche qui viene data la possibilità a chi gestisce il
paziente di inserire delle note aggiuntive riguardanti la famiglia,
ovviamente inerenti allo stato clinico e propense ad ottenere una
migliore diagnosi.
Patologie familiari
Nella prossima sottosezione vengono invece presentate le
informazioni sulle patologie di tutta la famiglia, cioè quelle persone con
legami di sangue con il paziente.
È qui presente una scheda riassuntiva del numero e di quali
patologie i familiari abbiano avuto. Per il dettaglio, invece, è anche
presente proprio un elenco di quali siano stati i membri della famiglia ad
avere avuto quella specifica patologia.
Questa sottosezione è molto importante soprattutto per stabilire se
ci siano possibilità di malattie genetiche e quindi ereditabili dal
paziente, o comunque connessioni fra malattie familiari e del paziente:
non solo collegamenti genetici ma magari anche di carattere ambientale
in cui vive il paziente.
27
Capitolo
3
–
La
cartella
clinica
Patologie del paziente
Nella sottosezione successiva invece si ha un resoconto completo e
dettagliato delle patologie che ha riscontrato precedentemente il
paziente. Anche qui, come nelle patologie familiari, è presente il
riassunto che fornisce quali patologie sono state riscontrate nel paziente.
Se si entra nel dettaglio, oltre alla patologia, come informazioni
utili vengono fornite l’età a cui è stata diagnosticata e, nel caso che ce
ne sia stato bisogno, il dettaglio del ricovero in ospedale. Infatti
vengono forniti i dati del ricovero ospedaliero: viene resa nota la data di
entrata e quella di uscita dall’ospedale, nonché informazioni su
quest’ultimo. Saranno presenti inoltre la diagnosi ricevuta dal paziente e
le note con cui è stato dimesso, per poter confrontare con una eventuale
nuova diagnosi.
In questa sottosezione comunque non devono per forza di cosa
essere inserite le patologie che hanno causato una permanenza in
ospedale, ma tutte quelle che il paziente ha avuto nell’arco della sua
vita.
Problemi fisiologici
Nell’ultima sottosezione dell’anamnesi sono presenti informazioni
mediche generali riguardanti il paziente. Infatti, vengono visualizzate
qui le note riguardo i problemi fisiologici del paziente quali la
digestione o il sonno, ma anche informazioni riguardo il gruppo
sanguigno del paziente e quello dell’eventuale partner, con la possibilità
di note aggiuntive riguardo proprio il gruppo sanguigno.
28
Capitolo
3
–
La
cartella
clinica
Ogni nota dovrebbe essere ben esaustiva, inquadrare subito il
problema e fornite anche più dettagli possibili: si deve ricordare che il
dottore non è a contatto diretto e quindi non può visitare di persona il
paziente.
3.4 Problemi clinici del paziente
Ora passiamo all’ultima parte da cui è composta la cartella clinica e
che rappresenta anche il vero punto in cui avviene lo scambio tra
l’esame digitalizzato dal requester, prelevato (tramite download) e
successivamente refertato dal dottore.
In questa sezione è presente un elenco di tutti i problemi clinici del
paziente in esame, con l’aggiunta di informazioni come la data, il
numero di esami svolti su ognuno e ovviamente lo stato di ogni evento.
Bisogna ora differenziare il discorso tra dottore e requester.
Il dottore ha la possibilità, una volta selezionato il problema clinico
da prendere in esame, diverse opzioni. Prima di iniziare a spiegare tali
opzioni è utile ricordare che il dottore può osservare tutti gli esami
svolti, ma può refertare solo i problemi riguardanti la sua
specializzazione.
Come prima cose deve selezionare l’esame svolto che vuole
refertare o comunque controllare: infatti è possibile che siano stati fatti
differenti esami per lo stesso problema clinico. I dati che emergono da
tale selezione sono quelli relativi al paziente, quali peso, altezza,
29
Capitolo
3
–
La
cartella
clinica
informazioni sulla pressione sanguigna, sulla frequenza cardiaca,
l’indice di massa corporea e infine delle conclusioni generali.
Successivamente può inserire un nuovo messaggio, con cui magari
può richiedere ulteriori informazioni in merito all’esame svolto;
scaricare sul proprio computer l’esame digitalizzato; refertare l’esame
selezionato compilando un form apposito. Questo form, uguale sia per
l’inserimento dei referti che dei messaggi, permette di inserire
informazioni a campo libero, tenendo pero a debita considerazione che
ogni referto e messaggio è associato al dottore che lo ha scritto.
Sono disponibili, inoltre, le opzioni per la visualizzazione di altri
messaggi e referti, nel caso si voglia tenere in considerazione una
seconda opinione. Attenzione a non dimenticare i vari stati di ogni
singolo problema clinico: dove il problema è classificato come “close” o
“reported”, il dottore ovviamente non potrà effettuare la refertazione o
aggiungere messaggi, infatti tale operazione è possibile solo per lo stato
“open” o “request another”.
L’interfaccia che si pone di fronte al requester è molto simile a
quella del dottore. Il requester da questa sezione può inserire i problemi
clinici relativi a quel particolare paziente. Alla creazione del problema
clinico vengono richieste alcune informazioni. Bisogna scegliere
innanzitutto come classificare il problema, così da poter coinvolgere il
giusto dottore specializzato: si sceglierà la categoria dell’esame in base
alle specializzazioni mediche così da avere un semplice legame medico
specializzato-problema clinico. A questo punto il requester deve inserire
i sintomi che tale problema ha mostrato e anche alcuni dati caratteristici
del paziente come l’altezza, il peso, la pressione sanguigna e la
30
Capitolo
3
–
La
cartella
clinica
frequenza cardiaca, l’indice di massa corporea, delle considerazioni
fisiche e una conclusione esaustiva sul tutto. Ovviamente è possibile
aggiungere un esame di laboratorio effettuato per tale problema e fare
l’upload sul server del file corrispondente.
Per quanto riguarda i problemi clinici già presenti, è possibile
inserire nuovi esami di laboratorio, così da dettagliare il problema. La
procedura è identica a quella per l’inserimento di un nuovo problema
clinico, anche se qui non si andrà a creare un problema clinico ma solo
ad aggiungere un esame a quello esistente, vengono comunque chiesti i
dati del paziente sopra citati in quanto magari possono essere cambiati.
Il requester può anche leggere i messaggi e soprattutto i referti dei
dottori che hanno risposto: ogni referto o messaggio contiene le
informazioni anche relative all’ora, alla data e soprattutto da quale
dottore questo è stato emesso.
Come sopra annunciato il requester può qui monitorare l’evento
decidendone la chiusura se è soddisfatto della refertazione o richiedere
una nuova opinione cambiando lo stato da “reported” in “request
another”. La possibilità di richiedere un’ulteriore analisi è a discrezione
del requester e dalla sua soddisfazione nel leggere le altre diagnosi: non
è prevista comunque nessuna limitazione in tal senso. Essendo nel
campo della telemedicina asincrona inoltre dallo stato di “close” è anche
possibile passare allo stato “request another”, in quanto magari il
problema non si è effettivamente risolto: questo può capitare per via
dell’inesperienza del requester, che si avvale di conoscenze mediche
non sempre all’altezza del problema che gli si pone e quindi potrebbe
anche non riconoscere eventuali sintomi presenti, considerando quindi il
problema risolto.
31
Capitolo
3
–
La
cartella
clinica
Come sopra prima accennato è qui che avviene il vero scambio di
informazioni tra requester, e quindi indirettamente tra il paziente, ed il
dottore.
Tutto il progetto MedTel si basa sullo scambio di tali informazioni
e finalizza il suo intento in una diagnosi più precisa e accurata possibile:
il tempo speso nel costruire la miglior cartella clinica possibile è quindi
tempo ben utilizzato per poter avere un risultato più corretto e rapido,
senza continue perdite di tempo dovute alla comunicazione asincrona tra
le due figure in gioco.
32
CAPITOLO 4 - GOOGLE WEB TOOLKIT
IL Google Web Toolkit (GWT) è un frame work di sviluppo per
applicazioni AJAX rilasciato con licenza open source Apache 2.0. Con
il GWT lo sviluppatore può creare applicazione AJAX in Java: ci si
porta quindi ad un livello di astrazione superiore di quello nativo
dell’AJAX, cioè senza scrivere codice HTML o JavaScript.
Attraverso l’uso di GWT è possibile quindi utilizzare i soliti IDE
disponibili per la creazione di progetti Java: nel nostro caso è stato
utilizzato Eclipse in primis perché open source, per via della sua
semplicità nel gestire progetti di medie-grandi dimensioni come il
nostro, nonché per la sua integrazione naturale con il GWT.
La pagina prodotta sarà comunque una pagina HTML contenente
codice JavaScript: il tutto viene eseguito da un compilatore Java-toJavaScript presente nel GWT.
GWT mette a disposizione dello sviluppatore delle librerie grafiche,
simili alle Swing, che permettono di creare applicazioni dalla grafica
avanzata: questi componenti sono chiamati widget. L’applicazione
creata non avrà nulla da invidiare alle altre applicazioni stand-alone
desktop, infatti l’obbiettivo principale di questo tool è quello di fornire
un’interfaccia immediata, sempre attuale e moderna. Sono messi a
disposizione una serie di widget nativi molto interessanti come alberi,
tabs ecc.
Inoltre nel nostro progetto abbiamo inserito anche delle librerie che
appunto mirano ad aumentare l’effetto grafico e a rendere il tutto più
coinvolgente. Le GwtExt infatti fondono il GWT con le librerie Ext,
33
Capitolo
4
–
Google
Web
Toolkit
ovvero delle librerie JavaScript che appunto creano nuovi effetti grafici.
Anche l’utilizzo di quest’ultime librerie è ovviamente open source.
Ora passiamo a descrivere le motivazioni per cui uno sviluppatore
dovrebbe utilizzare GWT rispetto allo scrivere codice JavaScript. La
motivazione principale sta tutta nel fatto che la tecnologia Java offre
diversi vantaggi nello sviluppo rispetto al Javascipt. Java verifica
staticamente i tipi di dato riducendo notevolmente gli errori a runtime ed
inoltre un’applicazione Java è più semplice da comprendere e
soprattutto gestire rispetto ad una JavaScript. Da non dimenticare poi
che per Java è presente un insieme molto più ricco di tool di sviluppo
come lo stesso Eclipse utilizzato da noi.
Un altro pregio è che con l’utilizzo del GWT e quindi del suo
compilatore, gli errori JavaScript non vengono commessi, in quanto il
compilatore di google non dovrebbe sbagliare nel passaggio da Java a
JavaScript. Con questo strumento quindi anche l’analisi e il debug è
molto più efficace in quanto possibile riga per riga e classe dopo classe,
come per una normale applicazione Java.
Un altro aspetto importantissimo è che l’utilizzo del GWT ci
permette di avere la completa compatibilità, almeno teorica, con i
browser più noti, come IE, Firefox, Mozilla, Safari ed Opera, senza
dover differenziare il codice sorgente: la dicitura “teorica” è dovuta al
fatto che alcuni comportamenti non sono esattamente gli stessi, ma se ne
parlerà meglio nel capitolo 6.
34
Capitolo
4
–
Google
Web
Toolkit
4.1 Caratteristiche
Un aspetto caratterizzante di GWT è la presenza del compilatore
che converte il codice Java in JavaScript: generalmente se
l’applicazione è compilata ed eseguita correttamente in hosted mode, il
codice Javascipt generato funzionerà ugualmente anche nel browser
scelto.
Come sopra detto il GWT si integra facilmente con Eclipse: con
una delle opzioni disponibili da riga di comando è addirittura possibile
creare un progetto con i file necessari per il funzionamento sotto
Eclipse.
Una delle principali caratteristiche del GWT resta comunque la
dinamicità e la possibilità di riutilizzare le componenti grafiche. I
programmatori infatti posso utilizzare classi già create e con queste
creare
ottime
e
soprattutto
sofisticate
applicazioni
grafiche:
l’interscambio di classi è uno dei punti di forza nell’utilizzo di GWT
come del resto anche del Java stesso e un po’ di tutti i linguaggi
orientati agli oggetti.
È facilmente possibile integrare librerie esterne, oltre a quelle di
GWT. Infatti anche le nostre GwtExt sono state integrate senza
problemi. Inoltre anche il codice JavaScript puro può essere inserito
direttamente nel codice sorgente Java: questo è possibile grazie alle
JavaScript Native Interface (JSNI). Naturalmente è possibile integrare
anche le numerose librerie esterne fornite dallo stesso Google, come le
API di Google Earth.
Un’altra importante caratteristica è la possibilità di una semplice
gestione della cronologia della navigazione. Un problema infatti delle
35
Capitolo
4
–
Google
Web
Toolkit
applicazioni AJAX è infatti quello dell’interazione con il browser. Nella
gestione della cronologia, l’applicazione deve “aiutare” il browser a
ricordare quale era lo stato precedente a cui, per esempio deve tornare il
browser: tutto questo sorge perché spesso in AJAX e quindi anche in
GWT l’applicazione è formata da una sola pagina, non da molte come
per un sito statico. Il GWT gestisce tale problematica con un
meccanismo che tiene traccia dello stato precedente, mediante l’utilizzo
di token, nella parte finale dell’url: viene segnalato lo stato in quel
momento e se successivamente basterà solo invocare tale stato tramite
un opportuno listener.
Come sopra detto, una delle caratteristiche principali è anche la
possibilità di scegliere il proprio ambiente di sviluppo. GWT non
impone niente in tal senso, infatti lo sviluppatore può utilizzare l’IDE
che meglio crede o quello con cui è più abituato a gestire i propri
progetti Java.
Un’altra caratteristica è la continua evoluzione. Essendo un
software open source, molte persone nel mondo stanno collaborando
alla creazione di nuovi ed interessanti componenti, nonché alla
risoluzione di problemi con le vecchie interfacce. Soprattutto per un
prodotto che punta molto sull’aspetto grafico, la continua evoluzione
grafica che ci offre questo tool è molto importante, soprattutto per avere
sempre un prodotto aggiornato.
Riguardo alle caratteristiche di funzionamento, le applicazioni
GWT possono essere eseguite in due modalità: Hosted mode oppure
Web mode. Passiamo ora alla descrizione di entrambe.
36
Capitolo
4
–
Google
Web
Toolkit
Hosted Mode
Nella Hosted mode l’applicazione viene fatta girare dalla Java
Virtual Machine (JVM): il tutto viene eseguito nel browser interno di
GWT. Questa modalità è utilizzata per effettuare il debug o comunque
per testare l’applicazione prima della pubblicazione: Eclipse permette
un’interfacciamento completo con l’avvio automatico durante i test del
browser interno di GWT. Molto del tempo nello sviluppare la nostra
applicazione è stato passato utilizzando questa modalità: infatti è
possibile effettuare il debug e testare sia il lato client sia il lato server
dell’applicazione, così da rendersi conto del corretto o scorretto
funzionamento.
Quando si avvia la modalità host ci si presenta davanti una shell di
sviluppo da cui si possono ricavare interessanti ed importanti
informazioni.
Figura 4.1
In primo luogo è presente una dicitura che ci conferma la partenza
della sessione HTTP con la relativa porta: viene lanciata ogni volta una
37
Capitolo
4
–
Google
Web
Toolkit
nuova istanza di Tomcat per permettere il corretto funzionamento delle
parti lato server.
È anche possibile visualizzare messaggi personalizzati, magari
generati ad un preciso evento, effettuando una chiamata a GWT.log().
Tale strategia può essere utile per segnalare le azioni compiute
dall’utente in fase di debug dell’applicazione.
Anche la gestione delle eccezioni è visualizzata all’interno di questa
shell: le eccezioni, sia catturate che non catturate, sono evidenziate in
rosso. Una finestra di log inoltre fornirà le informazioni sull’eccezione
generata, ovvero il tipo, la classe e la riga di codice in cui è accaduta e
lo stack di successione (fig 4.1).
È anche possibile utilizzare tale shell come strumento di debug
diretto, ovvero facendo stampare a video tutti i vari passi che vengono
compiuti in modalità host. Noi, nel nostro sviluppo, ci siamo comunque
affidati al debug “classico” offerto da Eclipse, anche se l’uno non
esclude l’altro.
Il punto da cui viene lanciato il browser necessario per l’hosted
mode è proprio la shell sopra citata. Il browser lanciato permette il
corretto funzionamento dell’applicazione e offre anche gli stessi
comandi di un comune web browser. Inoltre è anche presente, proprio
tra questi comandi, la possibilità di effettuare la compilazione del codice
Java lato client in codice JavaScript e avviare il browser predefinito.
38
Capitolo
4
–
Google
Web
Toolkit
Web Mode
Nella Web mode l’applicazione è costituita da codice Html e
JavaScript veri e propri: il compilatore produce tale codice che poi viene
caricato sul browser preferito. Questa sarà la vera e propria applicazione
che andrà ad essere inserita nel nostro web server, cioè in Tomcat.
Per passare dalla modalità host alla modalità web basta utilizzare
uno dei comandi principali del web browser di GWT (qui cerchiato in
rosso, fig. 4.2).
Figura 4.2
Quando si preme il pulsante la modalità host verrà interrotta e il
compilatore tradurrà il codice Java, le librerie GWT e le eventuali
librerie di terze parti, in codice JavaScript. L’utilizzo di questa modalità
è necessario per vedere come si comporta la nostra applicazione con le
varie tipologie di browser, senza dover effettuare realmente il deploy
module su un web server. Infatti soprattutto con la presenza di fogli di
stile è necessario testare il loro funzionamento sui differenti browser. Lo
39
Capitolo
4
–
Google
Web
Toolkit
stesso discorso vale per l’uso di librerie JavaScript di terze parti, che
non garantiscono lo stesso funzionamento su tutti i browser.
Inoltre l’utilizzo di questa modalità è anche un ottimo test per
valutare le prestazioni dell’applicazione: nella modalità host infatti il
tutto risulta essere ovviamente più lento perché non compilato in
JavaScript. Perciò soprattutto in presenza di molti widget e componenti
grafiche sarebbe opportuno utilizzare tale modalità prima della
definitiva pubblicazione.
4.2 Architettura
Un progetto GWT è costituito da tre package: il package principale che
è quello che conterrà il vero e proprio progetto, una directory /www in
cui il compilatore inserisce i file generati e la directory /tomcat creata
per il tomcat interno dell’hosted mode.
L’architettura vera e propria del progetto quindi si distingue in tre
directory principali contenute nella root del progetto: /public, /client e
/server. Oltre a queste tre directory è presente il file di configurazione
xml contenenti gli alias dei servlets, necessari per la mappatura su
Tomcat. Qui è definita anche la classe che implementa l’EntryPoint. Un
altro file xml è generato automaticamente quando si effettua il
deployment su Tomcat: è utilizzato come modulo di base comune. La
struttura di questi tipi di file verrà presentata nei capitoli successivi
quando si introdurrà il vero e proprio codice.
Nel package public sono inserite tutte le risorse statiche accessibili
dall’esterno. È qui presente la nostra pagina HTML su cui si svilupperà
il progetto: questa è anche la pagina HTML più importante. In tale
40
Capitolo
4
–
Google
Web
Toolkit
pagina devo anche essere inseriti i vari tag necessari per il
funzionamento corretto delle librerie esterne, come GwtExt. Inoltre in
questo package è anche possibile inserire eventuali pagine per
collegamenti interni al sito o anche delle immagini da visualizzare.
Nel package client sono presenti tutte quelle classi che fungono da
visualizzazione e da interfaccia grafica. Tutte queste classi sono dei
composite, eccetto una, quella che è l’implementazione di Entry Point e
che come detto farà solamente da contenitore del RootPanel per lo
scambio dei Widget da visualizzare. In queste classi sono presenti le
eventuali chiamate ai servlet, le RPC, che effettuano la chiamata alle
classi presenti nel package server.
Nel package server invece sono presenti i servlet necessari a
risolvere la dinamicità del portale. Tutte le interrogazioni a database
sono effettuate da queste classi, anche se non direttamente, ma previa
l’attivazione della procedura remota lato client. Anche la raccolta di dati
da file xlm avviene tramite queste classi, nella stessa maniera che per un
database.
4.3 Lato client e lato server
GWT si differenzia molto nella stesura delle pagine, soprattutto per
quanto riguarda il lato client ed lato server. La concezione di azioni
effettuate lato client e lato server si discostano dalle altre tecnologie
conosciute come ad esempio il PHP. Per poter quindi effettuare accessi
a database o reperire dati, bisogna effettuare delle chiamate remote,
dette RPC. Introduciamo gli elementi necessari per comprendere come
sia costituita la nostra applicazione, prima lato client e poi lato server.
41
Capitolo
4
–
Google
Web
Toolkit
I Widget
Le interfacce grafiche che vengono create con GWT sono molto
simili a quelle create dalle librerie Swing di Java. Nel JavaScript
tradizionale, la creazione di queste interfacce è fatta con la
manipolazione del DOM: utilizzando GWT questo avviene tramite delle
classi DOM, le quali vi accedono direttamente.
La creazione delle pagine lato client è ovviamente effettuata tramite
i widget, che non sono nient’altro che dei componenti grafici di alto
livello contenuti in dei particolari pannelli. Sono presenti i classici
componenti HTML, come i bottoni, i pulsanti di scelta multipla e scelta
esclusiva, le caselle di testo, e così via. In più vengono messi a
disposizione i widget particolari del GWT: particolari tipi di pulsanti,
come il Toggle Button, una serie di strutture atte alla creazione di menu
a tendina, le classiche strutture ad albero, passando anche per la struttura
a tabs.
Questi widget definiscono quindi il modo in cui l’utente esegue
azioni di input e di output, senza trascurare gli importanti effetti grafici
ottenuti.
I pannelli sono i contenitori di questi widget, nonché di altri
pannelli. Sono utilizzati per definire la struttura dell’interfaccia grafica
all’interno del browser. Vi sono numerose tipologie di pannelli:
strutturato a zone (nord, sud, ovest, est), per fasce orizzontali o verticali,
oppure con la classica struttura a tab (contenitore a sua volta di altri
pannelli).
Un particolare pannello è il RootPanel. Questo pannello è in cima
alla gerarchia dei pannelli ed è quindi quello che li conterrà tutti:
rappresenta infatti il <body> del documento HTML. Questo particolare
42
Capitolo
4
–
Google
Web
Toolkit
pannello è il luogo in cui vengono scambiate le varie “pagine” del
nostro portale, effettuando un’azione di rimozione e di aggiunta ogni
volta.
La gestione degli eventi in GWT è simile a quella delle Swing,
ovvero viene utilizzato il concetto di “listener”. Questo listener non è
nient’altro che un’interfaccia che definisce uno o più metodi che il
widget chiama quando si verifica l’evento. Ogni widget ha una sua lista
personalizzata di eventi chiamabili, cioè che si possono verificare. Un
classico esempio è il click del bottone. Il listener associato al bottone è
il ClickListener, il quale al suo interno avrà un metodo onClick(): esso
si attiverà al click sul bottone e se giustamente implementato eseguirà
l’azione voluta dall’utente. Ovviamente tale evento necessita di
parametri per essere eseguito correttamente, perciò si deve fornire il
widget stesso come parametro. Questo e molti altri esempi saranno
presenti nella sezione relativa alla stesura del codice, in quanto, ogni
azione possibile dell’utente è gestita tramite i listener.
I widget di GWT, essendo in fondo dei componenti HTML,
possono anche essere integrati con i classici fogli di stile (CSS). Ogni
componente e quindi classe, di default, ha una sua regola di stile così
chiamata: gwt-<nomeclasse>. Per esempio il widget Button, che
rappresenta il bottone, avrà gwt-Button. Le regole utilizzabili per
manipolare i widget sono quelle tradizionali utilizzate per i componenti
HTML. Si possono assegnare stili anche utilizzando alcuni metodi
disponibili per la classe widget di interesse, come setStyleName(). Una
cosa importante da tenere presente è che le regole di stile o il foglio di
stile esterno devono essere collocati nella parte statica del progetto,
ovvero nella directory /public, ed eventualmente inseriti tramite
43
Capitolo
4
–
Google
Web
Toolkit
l’opportuno codice nella pagina principale (tag <link>) in caso di CSS
esterno.
L’assemblaggio di questi widget in pannelli permette la creazione
di una nuova struttura, detta composite. Il composite non rappresenta
nient’altro come verranno mostrati i widget: ogni composite, è quindi,
per così dire, una “pagina” del nostro portale, anche se questo non è
propriamente vero. Infatti un composite può anche essere la base di più
pagine, in quanto, essendo il sito dinamico, esso può cambiare aspetto a
seconda delle informazioni richieste e ricevute in quel momento. Inoltre,
come più volte detto, il concetto di pagina web in realtà viene un po’
meno, perché la pagina in cui si sviluppa tutto il portale è sempre la
stessa, l’unica cosa che cambiano sono i composite caricati sul
RootPanel.
Per scrivere un modulo di un’applicazione in GWT, inizialmente
bisogna creare una sottoclasse di EntryPoint, una classe particolare che
rappresenta anche l’unica pagina del nostro portale. Questa sottoclasse
sarà quella che avvierà il primo composite e che apparirà come
schermata iniziale del portale (la finestra di login).
Un’importante caratteristica di queste classi, è che in esse deve essere
solo inserito codice traducibile dal compilatore GWT, altrimenti lo
stesso compilatore ci fornisce errore: il codice contenuto in questi
composite, o comunque all’interno del costruttore degli stessi, deve
essere GWT compatibile, cioè contenti nelle apposite librerie. Tutto
questo è dovuto al fatto che il codice verrà tradotto il JavaScript e
quindi, come logicamente ci si può immaginare, non tutto il codice Java
si presta bene a questa traduzione. Si possono comunque creare dei
44
Capitolo
4
–
Google
Web
Toolkit
metodi che contengono codice Java “classico”, senza incorrere in
nessun problema.
Le Remote procedure Call (RPC)
Ogni volta che il browser ha bisogno di interagire con il server, o
per memorizzare dati o per raccoglierne, viene attivato il codice lato
server tramite una procedura remota, detta Remote Procedure Call
(RPC). Essa non è nient’altro che una richiesta effettuata tramite HTTP.
GWT effettua questo meccanismo di RPC tramite l’uso dei Java Servlet,
i quali accedono alle risorse del server. Le classi presenti dal lato server
infatti sono classi Java che non verranno tradotte dal compilatore GWT
ed è proprio con queste classi che viene effettuata la connessione al
database MySQL e anche tutte le interrogazioni per reperire i dati.
Passiamo ora ad analizzare più vicino questo meccanismo di interazione
client-server.
Una fondamentale differenza tra le applicazioni AJAX e le
tradizionali applicazioni HTML è che le applicazioni AJAX non
necessitano di caricare una nuova pagina per il loro funzionamento.
Comunque anche le applicazioni AJAX hanno la possibilità di
raccogliere dati dal server, proprio tramite le sopracitate RPC. Il
meccanismo delle RPC è molto semplice e permette di passare oggetti
Java avanti e indietro tramite il protocollo HTTP. Tale meccanismo può
sembrare a prima vista complicato, ma ci si rende conto che porta a
notevoli vantaggi, quali la riduzione della banda utilizzata ed in generale
l’aumento di tutte le prestazioni. Il codice lato server che viene invocato
dal lato client è detto anche servizio.
45
Capitolo
4
–
Google
Web
Toolkit
Ora passiamo alla struttura vera e propria della nostra procedura
remota, enunciando le principali classi ed interfacce presenti. Alcune di
queste classi ed interfacce sono fornite dal GWT, altre devono essere
create dall’utente e altre ancora generate automaticamente, come la
classe service proxy. Ecco qui di seguito un diagramma che illustra
quanto detto.
Figura 4.3
Per creare un servizio sono quindi necessari i seguenti passi:
1. Definire un’interfaccia del tuo servizio che estenda l’interfaccia
RemoteService, nella quale vi siano presenti tutti i metodi
necessari per la RPC.
2. Definire una classe che contenga tutto il codice lato server
necessario, che estenda la classe RemoteServiceServlet e che
implementi l’interfaccia creata al passo precedente. Questa classe
sarà il nostro servlet vero e proprio.
3. Definire un’interfaccia asincrona che verrà chiamata dal codice
lato client e permetterà il corretto funzionamento.
46
Capitolo
4
–
Google
Web
Toolkit
Introduciamo ora il concetto di interfaccia sincrona e asincorna. La
prima interfaccia creata è un’interfaccia sincrona e viene inserita nel
codice lato client. Tale interfaccia rappresenta la definizione del servizio
che si sta creando ed il servizio lato server dovrà implementare questa
interfaccia.
Per funzionare, però, oltre all’interfaccia precedente è necessario
anche di un’interfaccia asincrona, perché non è infatti possibile
chiamare la RPC direttamente dal lato client. Questa interfaccia è basata
sull’interfaccia precedente e richiede che oltre ai precedenti parametri di
ogni metodo, sia presente un oggetto AsyncCallback, il quale conterrà le
informazioni desiderate provenienti dal server. I metodi di questa
interfaccia sono chiaramente di tipo void in quanto non necessitano
niente come dato di ritorno.
Una cosa importante da ricordare è la collocazione ed i nomi delle
interfacce sopra citate. Entrambe devono stare nello stesso package,
ovviamente nel lato client. Per quanto riguarda la denominazione,
devono avere lo stesso nome, con il suffisso Async per l’interfaccia
asincrona. Inoltre ogni metodo presente nell’interfaccia sincrona deve
essere presente nell’interfaccia asincrona e come lista dei parametri
deve avere la stessa con l’aggiunta, per ultimo, del parametro di tipo
AsyncCallback.
Vediamo ora come è costituita la classe lato server. Tale classe è
basata sull’architettura dei servlet Java, deve implementare la
RemoteServiceServlet e l’interfaccia sincrona. Attenzione a non
implementare l’interfaccia asincrona. L’unica differenza con un normale
servlet sta nel fatto che invece di estendere HttpServlet, essa estende
RemoteServiceServlet.
RemoteServiceServlet
47
si
occupa
della
Capitolo
4
–
Google
Web
Toolkit
serializzazione e deserializzazione dei dati tra il client ed il server: è
proprio questa classe ad estendere HttpServlet.
Ora un piccolo accenno va fatto riguardo all’uso di file xml per la
configurazione e mappatura dei servlet. All’interno del modulo xml
viene utilizzato il tag <servlet> per identificare e mappare tali servlet.
Vengono aggiunti due importanti parametri: il parametro path e il
parametro class. Il parametro path serve per assegnare lo specifico URL
che il servlet avrà quando sarà instanziato. Il parametro class invece
serve proprio ad identificare quale sarà la classe riferita a quel servlet,
cioè in quale package il servlet sia presente.
Passiamo ora ad illustrare il meccanismo vero e proprio con cui tale
RPC viene eseguita. Il processo con cui il nostro servizio è invocato è
sempre lo stesso.
1. Istanziare il servizio usando il metodo GWT.create().
2. Viene creato un oggetto AsyncCallback che conterrà
l’informazione del completamento della RPC.
3. Viene effettuata la chiamata.
L’oggetto AsyncCallback, creato al punto 2, sarà il fulcro delle
operazioni di ricezione dei dati richiesti tramite la RPC. Infatti tale
oggetto conterrà due metodi: il medoto onSuccess() e il metodo
onFailure(). Il primo metodo, come si deduce dal nome, è invocato
quando la chiamata remota ha esito positivo, cioè il collegamento con il
servlet è riuscito. L’altro metodo invece viene invocato quando la
connessione con il servlet fallisce. Le possibilità che tale connessione
fallisca sono dovute ad un’errata stesura del file di mappatura dei
servlet, o alla mancanza, per qualunque motivo, del file sevlet stesso.
Attenzione
a
non
confondere
48
questo
fatto
con
la
riuscita
Capitolo
4
–
Google
Web
Toolkit
dell’interrogazione a database: infatti se dovesse avvenire un’eccezione
lato server o comunque avvenire qualche errore sempre nel servlet,
viene eseguito il metodo onSuccess().
Questi due metodi forniscono all’utente anche la possibilità di
utilizzare dei parametri. Per il metodo onSuccess() è presente il
parametro result di tipo Object, che rappresenta il risultato della RPC.
Questo è ovviamente di tipo Object perché l’utente può far tornare
qualunque tipo serializzato dalla RPC: il cast quindi è sempre safe per i
tipi serializzati. Il parametro disponibile per il metodo onFailure() è
invece caught di tipo Throwable, cioè è possibile utilizzare tale
parametro per prelevare informazioni riguardo l’eccezione o l’errore
creatosi.
I dati che vengono passati tra client e server non sono dati
qualunque. GWT, infatti, supporta il concetto di serializzazione. Tale
concetto permette l’estrapolazione del contenuto di dati da una parte di
codice in esecuzione, la quale può essere o trasmessa ad un’altra
applicazione memorizzata e utilizzata successivamente. Quindi sia i
parametri che i dati di ritorno dei metodi utilizzati nelle RPC devono
essere serializzabili, rispettare cioè particolari restrizioni. Non bisogna
confondere i concetti di serializzazione del GWT con quelli
dell’interfaccia Java Serializable, in quanto sono simili ma non uguali.
Un tipo è serializzabile secondo il GWT se rispetta uno dei seguenti
punti:
• Il tipo di dato è una primitiva, come char, byte, int, long,
boolean, float o double.
49
Capitolo
4
–
Google
Web
Toolkit
• Il tipo di dato è un’istanza di String o di Date, o un tipo
wrapper come Character, Byte, Short, Integer, Long,
Boolean, Float o Double.
• Il tipo è un’enumerazione, tramite la parola chiave enum.
• Il tipo è un array di tipi serializzabili.
• Il tipo è definito dall’utente come serializzabile, tramite
Serializable o IsSerializable.
• Il tipo ha almeno una sottoclasse serializzabile.
In conclusione si può dire che l’utilizzo delle chiamate server, non è
poi così complicato, anche se magari si discosta un po’ dalle altre
tecnologie come PHP o ASP. Il tutto comunque punta ad aumentare le
prestazioni in quanto con le applicazioni AJAX si dovrebbe evitare di
ricaricare tutta la pagina e quindi velocizzare il tutto. Confronti con le
altre tecnologie sono lasciati al capitolo riguardante le conclusioni.
50
CAPITOLO 5 - SOLUZIONI TECNICHE
CARTELLA CLINICA
Vengono presentate ora le soluzioni tecnologiche utilizzate per la
realizzazione della cartella clinica, seguendo l’ordine di presentazione
del capitolo 3.
Una considerazione che vorrei fare sugli argomenti trattati
successivamente è che verrà utilizzato impropriamente il termine pagina
nei paragrafi successivi. Questo termine non è rappresenta la realtà se si
considera che con la tecnologia GWT la pagina è sempre la stessa, ma
non perde neanche di significato se tale termine è utilizzato per
esprimere le varie “viste” disponibili di fronte all’utente: con il termine
pagina verrà quindi identificato ogni Composite visualizzabile
dall’utente e sarà tratto come una pagina a sé.
5.1 Comʼè fatta
La cartella clinica è stata concepita cercando di renderla più
semplice possibile da utilizzare. A questo proposito abbiamo deciso di
basarci su modelli già conosciuti, così da non introdurre ulteriori
difficoltà di comprensione. Come base è stata scelta la modalità con la
quale il sistema operativo MS Windows propone la risoluzione
nell’esplorazione delle cartelle o dei file. Infatti ci è sembrata la
soluzione più ovvia dato che, come bene noto, a oggigiorno, i sistemi
operativi Microsoft sono i più diffusi, e quindi anche quelli che, di
conseguenza, la gente è abituata ad utilizzare.
51
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
La struttura è formata, quindi, da due aree differenti: una laterale
sinistra ed una maggiore sulla destra che ricopre il resto della cartella.
La parte laterale sinistra è formata con una struttura ad albero. Con
questa soluzione sono possibili due agevolazioni importanti: la prima
riguarda il fatto che l’utente ha sempre sotto controllo la posizione in
cui sono i dati, la seconda e più importante è che in questo modo, nel
lato sinistro della cartella clinica si ha sempre una panoramica generale
dei dati clinici del paziente. Ovviamente la struttura ad albero è generica
per tutti i pazienti, ma a seconda di quali informazioni cliniche vengono
inserite, tale struttura si modifica dinamicamente: ogni nodo sarà un
dato clinico sensibile del paziente ed è con esso che l’utente interagisce.
Per rendere il tutto più coinvolgente abbiamo anche utilizzato delle
icone che per noi rappresentavano al meglio ogni ramo dell’albero: un
esempio può essere visto in figura 5.1.
Figura 5.1
La restante parte della cartella clinica ovviamente è dove vengono
visualizzati le informazioni non più sotto forma di elenco, ma nel loro
dettaglio. La struttura utilizzata è una struttura a tab, i quali permettono
52
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
di avere una più rapida manipolazione dei dati, una memoria delle
schede aperte in precedenza. Questa soluzione, utilizzata anche da molti
browser, rende la cartella clinica più simile alla realtà, infatti permette di
avere delle schede per ogni dato clinico del paziente, come le schede di
un raccoglitore che potrebbe utilizzare nella realtà il medico.
L’organizzazione in tab permette di sfruttare tutte le comodità che da
questa derivano, come la possibilità di avere più schede aperte
contemporaneamente (anche se visualizzate una per volta). In questa
area le soluzioni di visualizzazione sono differenti per ogni sottosezione
della cartella clinica e verranno dettagliatamente affrontate.
L’accesso alle singole schede è effettuato in maniera semplice
grazie alla selezione di un nodo nell’albero laterale: al click su uno di
questi, viene aperto un tab che visualizza le informazioni ricercate.
Abbiamo utilizzato anche una semplice colorazione per rendere il tutto
più user-friendly, ma non solo. Il colore di contorno della cartella
clinica, come quello della barra del titolo, sono differenziati per ogni
tipologia di utente: il requester avrà un colore ed il dottore un altro.
Oltre a queste due aree sono disponibile alcuni strumenti per
interagire con i dati, utili soprattutto per il requester. Sono infatti
disponibili dei menu a tendina che permetto, dove possibile ed
implementato, di modificare, inserire o cancellare i dati corrispondenti
alla pagina visualizzata. Oltre a questi strumenti sono presenti i classici
pulsanti di chiusura, di minimizzazione o massimizzazione della cartella
clinica, ed anche un pulsante di help con la guida in linea sul suo
utilizzo. Questa guida è stata necessaria perché il software creato può
essere utilizzato da chiunque e quindi la sua diffusione deve essere
accompagnata da una guida semplice ed esaustiva.
53
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
Tutto questo è stato effettuato utilizzando la tecnologia del GWT.
Qui di seguito verranno analizzate le singole pagine, così da permettere
la comprensione e l’utilizzo di questa tecnologia: si passerà ad
analizzare ogni pagina partendo dalla struttura base, cioè dai pannelli,
passando per i dettagli grafici, come i vari widgets, concludendo con le
RPC presenti.
Bisogna ricordare inoltre che ogni cartella clinica è personalizzata
per ogni paziente e non fornisce alcuna informazione sugli altri presenti
nel database. Il funzionamento con cui ogni cartella clinica è generata è
molto semplice. Infatti nella sezione requester o dottore compare un
elenco dei vari pazienti disponibili da quell’utente, il quale selezionando
lo stesso, avvia la procedura di apertura e visualizzazione della cartella
clinica. La cartella che qui si apre è quindi in realtà un pop-up, così da
poter mostrare, in sfondo, l’elenco di partenza. Con questo metodo si è
voluto far avere all’utente una memoria delle azioni da lui stesso
compiute: anche se il pop-up, per chi è abituato all’utilizzo di internet,
può sembrare poco risolutivo, nella comprensione di un nuovo software
invece resta una soluzione valida, perché non “nasconde” l’azione
precedente. Le finestre utilizzate per questo pop-up, oltretutto, sono
graficamente efficienti, con trasparenze molto efficaci, che rendono il
prodotto molto evoluto ed innovativo.
Quest’utilizzo di pop-up quindi ha reso inutile la creazione del
meccanismo di cronologia citat nel capitolo di presentazione del GWT,
in quanto l’utente ha sempre di fronte la pagina precedentemente
utilizzata.
54
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
5.2 ClinicalFolder
Come primo argomento verrà affrontata proprio la struttura ed il
codice che compone la cartella clinica. Innanzitutto bisogna ben
spiegare cosa s’intende effettuare con questa classe. La classe cartella
clinica funziona da contenitore e da visualizzatore delle varie sezioni. In
questa classe sono presenti innumerevoli meccanismi necessari a far
funzionare le altre classi e soprattutto a far interagire queste fra di loro.
Oltre a funzionare da tramite tra le classi delle varie sezioni, è qui
presente la costruzione dell’albero laterale. Anche la parte puramente
grafica della struttura della cartella clinica è curata in questa classe. Non
sono invece presenti i contenuti degli eventuali tab aperti in fase di
visualizzazione o le eventuali finestre di pop-up: queste sono separate e
vengono trattate nelle sezioni successive di questo capitolo.
L’attivazione della cartella clinica, avviene quando un dottore o un
requester, tramite la propria interfaccia grafica, seleziona un paziente
nonché un problema clinico. Nel primo caso come tab iniziale viene
visualizzato il profilo del paziente, mentre nel secondo l’attenzione è
puntata sul problema scelto.
La pagina viene aperta su di una finestra, ovvero grazie al widget
Window delle librerie Gwt-Ext. In questa finestra vengono aggiunte le
varie strutture grafiche, quali l’albero ed il TabPanel che conterrà i tab.
Molte ed importanti sono le proprietà che questa finestra possiede: dalla
posizione dei pannelli tramite a degli appositi Layout, passando per la
gestione delle icone di massimizzazione e minimizzazione, nonché
dell’help in linea.
Analizziamo ora l’albero laterale presente in questa finestra. Alla
base vi è presente un pannello particolare, il TreePanel. Questo pannello
55
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
è necessario per l’inserimento della struttura ad albero, in quanto
permette di interagire con diverse proprietà. Oltre alle proprietà
generali, è qui che bisogna impostare il nodo radice dell’albero. La
costituzione dell’albero infatti è su scala gerarchica, ovvero permette un
solo nodo principale e successivamente vi sono tutti i nodi figli, che a
loro volta ne possono contenere altri. Nel nostro caso particolare
abbiamo dovuto dividere l’albero in due parti: una parte statica ed una
asincrona (dinamica). La parte statica rappresenta tutti quei nodi che
non modificano la loro struttura, ovvero lasciano inalterata la parte
grafica ma anche le varie proprietà. La parte asincrona invece è
necessaria per tutti quei nodi che invece possono variare in struttura,
quindi magari variando il proprio titolo di visualizzazione nonché
alcune proprietà. È quindi stata utilizzata per l’anamnesi e tutte le varie
sottosezioni.
Figura 5.2
La parte sincrona è creata essenzialmente tutta allo stesso modo.
Vengono come prima cosa impostate le proprietà necessarie, come
l’identificativo nell’albero. Successivamente viene impostato un evento
che descrive l’azione da compiere quando viene selezionato il nodo in
questione: si dovrà aprire il tab rispettivo nel pannello dei tab,
56
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
controllando ovviamente che tale già non vi sia presente, altrimenti
portarlo in primo piano. Avviene quindi in tale metodo la costruzione
del tab con la scelta dell’effettiva vista da mostrare e l’aggiunta della
toolbar dove necessaria. Il modo di avvalersi dell’evento è sfruttato
ugualmente anche per la parte asincrona, anche se in modo leggermente
differente.
Si analizza ora la parte asincrona. È necessario come prima cosa
impostare correttamente l’oggetto che carica i dati che formeranno tale
albero: l’XMLTreeLoader. Come si intuisce dal nome, questo loader
preleva i dati in formato XML e li analizza in base ai tag, costruendo
quindi vari nodi degli alberi. Il codice XML è costruito su una classe a
parte, che non fa altro che effettuare una serie di query alle tabelle
contenente i dati dell’anamnesi. Il risultato di ogni query viene utilizzato
per costruire una stringa: tale stringa contenente codice XML, viene
inviata tramite il metodo doPost() delle HttpServlet al richiedente, cioè
all’XMLTreeLoader. Questa stringa viene generata ogni volta che si
invoca il loader, ovvero quando si richiede di rigenerare l’albero. Il
nodo dell’albero asincrono avrà un costruttore differente rispetto a
quello precedente: viene generato tramite l’oggetto AsyncTreeNode che
metterà
a
disposizione
il
metodo
reload()
fondamentale
per
l’aggiornamento.
Il meccanismo che genera la creazione del tab alla selezione del
nodo asincrono, è simile ma non uguale a quello prima descritto. Infatti
la differenzia sostanziale, sta nel fatto che non si sa a priori che tab
aprire. Si è quindi risolta questa situazione impostando, già in fase di
generazione del codice XML per il loader, di dotare ogni nodo di un
proprio identificatore dinamico, ovvero prelevato da database. In base
alla corrispondenza con questo id viene aperto il tag rispettivo.
57
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
Tramite una serie di metodi richiamati si evidenziano due possibili
scenari. Il primo coinvolge la creazione del tab necessario alla
visualizzazione delle pagine di riepilogo, ovvero i nodi asincroni di
primo livello appena sotto anamnesi. Qui l’id non è nient’altro che il
nome della tabella da cui vengono prelevati. L’altro scenario invece si
presta quando è necessaria la creazione di “foglie”, ovvero di nodi di
secondo livello, sottostanti ai precedenti. In questi nodi l’id invece è
dato da una sottostringa dell’id del genitore (una sottostringa dell’id
prima descritto) con in più il valore prelevato database. Quest’ultimo
valore non è nient’altro che l’id del record di dati nella tabella
corrispondente. Infatti tale valore viene anche settato nella sessione
corrente, così da permettere una più semplice esecuzione delle query di
recupero informazioni necessarie per le altre classi. Si vuole avere
quindi sempre la traccia univoca di quale record attuale si sta trattando.
Tutta questa procedura è effettuata tramite una RPC, che nel servlet
non fa nient’altro che impostare il valore in sessione. Al buon fine della
chiamata, il controllo ritorna al client che tramite l’apposito metodo
seleziona ed aggiunge il tab corretto al TabPanel.
Viene presa in esame quindi la gestione del TabPanel.
Quest’ultimo, come dice lo stesso nome conterrà i vari tab atti alla
visualizzazione dei dati richiesti. L’aggiunta di un tab è molto semplice.
Tra le varie proprietà importanti da citare è che ogni tab è riconosciuto
all’interno del pannello tramite un id. Sono inoltre presenti due tipi di
tab, quelli attivi cioè in primo piano e quelli inattivi, prelevabili tramite
un opportuno metodo del TabPanel. Queste proprietà saranno molto
importanti quando avverrà l’aggiornamento dei tabs.
58
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
Per quanto riguarda i tab iniziali, essi vengono scelti in base a quale
schermata sorgente attivi la cartella clinica. Questa scelta viene operata
tramite l’interazione di alcuni metodi contenuti in questa classe e nella
classe sorgente, ovvero tramite il passaggio di determinati parametri.
Un’altra importante procedura che viene affrontata in questa
pagina, è quella del prelevamento di alcune fondamentali informazioni
per migliorarne l’aspetto grafico e funzionale. Queste coinvolgono
soprattutto la selezione del composite da visualizzare in alcuni tab e la
creazione della toolbar. Il problema si pone solamente per le sezioni
riguardante i dati dei genitori e quella relativa ai problemi fisiologici.
Questo avviene perché tali sezioni sono descritte da una sola pagina e
non permettono ulteriori dettagli, quindi non hanno nodi figli al loro
seguito. È necessario che si abbia la conoscenza se tali dati sono stati
inseriti oppure no al fine di modificare la struttura grafica. Infatti nel
caso di assenza di dati, verrà visualizzato un messaggio che notifica tale
situazione all’utente. Viceversa, in caso di presenza, viene attivata la
classe necessaria per la visualizzazione dei dati.
La stessa procedura per la toolbar: quando non vi sono
informazioni ovviamente verrà mostrato il pulsante di inserimento,
altrimenti quello di modifica e cancellazione. Come detto questo non
avviene per le altre sezioni perché esiste sempre una pagina riassuntiva
della sezione ed il messaggio da mostrare è gestito in tale pagina. Lo
stesso per la toolbar, in quanto il pulsante che permette il nuovo
inserimento sarà sempre presente nella pagina appena citata.
Naturalmente il recupero di tali informazioni è effettuato tramite una
RPC, la quale non fa altro che verificare se sono appunto presenti righe
con il record di informazioni richieste e quindi costruire la pagina di
conseguenza.
59
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
Una parola in più va spesa riguardo alla toolbar. Questa struttura è
stata progettata per contenere le varie opzioni disponibili. La scelta è
caduta su questo widget in quanto ci permette di avere la possibilità, in
futuro, di ampliare con quante opzioni si desideri il nostro portale. La
toolbar infatti è creata mediante l’aggiunta interna di ulteriori widget,
chiamati Item. Questi oggetti possono effettuare qualunque tipo di
operazione associata al proprio listener: nel nostro caso alla selezione di
esso vengono avviate sia procedure interne a questa classe, sia aperte
delle nuove classi. Inoltre ogni menu che si viene a creare non
interferisce con la creazione o la struttura del tab. Proprio da qui nasce
la possibilità tendenzialmente infinita di incrementare tali opzioni.
Passiamo ora ad analizzare le altre procedure presenti in questa
classe. Una delle procedure più interessanti e che viene richiamata dalle
altre pagine aperte dalla toolbar è quella riguardante l’aggiornamento
dei tab. L’operazione svolta è molto semplice quanto essenziale per
avere una vista sempre aggiornata. Vengono passati come parametri due
tab, il primo da togliere e l’altro da aggiungere. In realtà tali tab sono gli
stessi, a parte le modifiche aggiornate sul secondo. Come prima cosa
viene impostata quella proprietà di cui deve godere il secondo tab per
essere riconosciuto all’interno della cartella clinica, ovvero l’id.
Successivamente non si fa altro che rimuovere il vecchio tab,
aggiungere il nuovo e renderlo attivo (selezionato). Considerando la
velocità di tali operazioni, l’effetto ottenuto è quello di aver aggiornato
il primo tab, non di averne creato uno identico sostituto a questo.
Una serie di importanti procedure sono quelle riguardanti la
creazione, modifica e cancellazione di un dato clinico. Se la creazione e
la modifica non fanno altro che avviare in differenti modalità la classe
specifica della loro sezione, la cancellazione avviene interamente in
60
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
questa classe. La procedura remota viene effettuata al click sul pulsante
di cancellazione. Nel metodo del servlet non viene fatto altro che
eseguire una query di cancellazione, differente a seconda di che dato si
stia considerando. Infatti tramite l’identificatore del nodo di ogni ramo e
quindi di ogni dato clinico, viene dapprima riconosciuta e selezionata la
giusta tabella del database sulla quale verrà effettuata la query.
Successivamente si preleva dalla sessione l’id del paziente in esame e si
avvia la query. Ritornato il controllo nel lato client, non si deve far altro
che
rimuovere
il
tab
sottostante
e
aggiornare
l’albero
(per
aggiornamento si intende la sola parte asincrona).
In questa classe sono presenti anche le operazioni di controllo sul
decidere quale classe deve essere aperta della sezione relativa ai
problemi clinici: viene infatti controllato se l’utente loggato è un
requester o un dottore. Tale controllo serve ovviamente anche nella
decisione di visualizzare la toolbar, in quanto questa non è visualizzata
se si è un dottore.
La creazione dell’help in linea è stato qui implementato, ma solo
parzialmente. Infatti viene solamente creata la maschera iniziale
dell’help (fig. 5.3), non le successive pagine, che sono invece pagine
HTML pure. La maschera non è nient’altro che una pagina HTML, che
tramite dei tag ancora <a> richiamerà le varie pagine più dettagliate
dell’help. Anche tale struttura è soggetta a controlli di tipo condizionale
in base all’utente loggato e quindi verranno visualizzati alcuni link
piuttosto che altri.
61
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
Figura 5.3
Nel complesso la creazione di questa classe ha creato diversi
problemi, in quanto interagisce con altre classi, non tutte uguali. Per
cercare di progettare una struttura solida ci siamo avvalsi dell’aiuto
delle sessioni per il passaggio degli identificatori principali. Dal punto
di vista del codice, sono stati creati il più possibile dei metodi autonomi
così da suddividere l’informazione in ognuno di essi: la modifica
parziale ma anche totale di una procedura è così più semplice ed
immediata perché coinvolge solo quel metodo. Un elenco completo di
tutti questi metodi può essere osservato dal codice sorgente presente
nell’appendice finale di questa tesi.
5.3 Patient Profile
Le pagine che qui andremo a descrivere riguardano i dati non di
tipo medico presenti nella cartella clinica: verrà mostrata la struttura
delle pagine necessarie a creare il profilo del paziente.
La prima pagina o classe di cui parleremo è la PatientProfile. . Lo
scopo di questa pagina è quello di visualizzare tutte le informazioni
riguardanti il profilo del paziente, come la data di nascita, informazioni
62
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
sull’indirizzo, ecc. Ovviamente, come detto, ogni classe e quindi anche
questa, estende la superclasse Composite, utili per aggregare i numero
widget presenti. La pagina sarà composta da varie etichette, o label, che
visualizzeranno i dati richiesti da database. Come pannello di base
abbiamo utilizzato un AbsolutePanel, ovvero un pannello che consente
di posizionare le varie etichette tramite delle coordinate cartesiane, così
da essere precisi negli allineamenti. La tecnica utilizzata per la
visualizzazione dei record da database è molto semplice e intuitiva. Si è
pensato di utilizzare delle label per indicare quale dato veniva
visualizzato e delle label differenti per visualizzare i dati effettivi:
queste label all’inizio sono ovviamente vuote, cioè senza niente scritto,
ma al caricamento della pagina vengono riempite con i dati provenienti
dalla RPC. Le label utilizzate sono ovviamente quelle del Gwt-Ext, in
quanto forniscono una grafica migliore e dei metodi aggiuntivi rispetto
alle classiche di GWT. La distribuzione di queste label è stata effettuata
su due colonne, così da poter essere visualizzato tutto si di una pagina.
Alla prima tipologia di label è stato dato uno stile uguale per tutte
cioè un carattere grassetto, così da evidenziare meglio ogni campo. Alla
seconda tipologia di label, invece, è stato dato uno stile differente,
impostando solo la dimensione del carattere, uguale alle precedenti. Per
ognuna di queste label, ma soprattutto per quelle atte a visualizzare i
dati provenienti da database, è necessario un nome rappresentativo:
tramite tale nome la label sarà riconosciuta all’interno del composite.
Analizziamo ora il meccanismo della chiamata asincrona con cui
reperiremo i dati dal database. Viene come prima cosa istanziato il
servizio, poi creato l’oggetto AsyncCallback. Nel metodo onSuccess()
verranno eseguite le operazioni di riempimento delle label: i dati
provenienti dal servlet sono ovviamente dati serializzati, perciò si è
63
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
deciso di utilizzare l’oggetto ArrayList come dato di ritorno, il quale
conterrà tutti i risultati della query da database. Viene creata una
variabile text di tipo ArrayList effettuando proprio un cast a result.
Tramite il metodo setText() delle label, viene impostato il testo da
visualizzare: bisogna però tuttavia far notare che i dati proveniente da
database potrebbero non essere completi, perciò si è deciso di
visualizzare solo i dati non nulli, tramite un’opportuna struttura
condizionale.
Nel metodo onFailure() invece viene mostrato all’utente un errore,
con la motivazione del fallimento della connessione al servlet: più che
altro tale metodo serve in fase di diagnostica del sito da parte di noi
sviluppatori, in quanto una volta creato e mappatto correttamente il
sevlet tale errore non dovrebbe più essere mostrato.
Dopo la creazione dell’oggetto AsyncCallback finalmente viene
effettuata la chiamata. Il metodo necessario viene evocato tramite
l’utilizzo della variabile patient, la quale è del tipo dell’interfaccia
asincrona: sarà presente come parametro solo callback, di tipo
AsyncCallback, il quale eseguirà appunto i metodi sopra citati.
Questo era quanto presente nel codice lato client, ora passiamo a
trattare invece il codice lato server. Qui troveremo il metodo view(), che
come parametro di ritorno ha, come sopra detto, un ArrayList.
Innanzitutto è necessario recuperare i dati dalla sessione per poter avere
l’id del paziente, ovvero il riconoscimento univoco nel database. Viene
quindi effettuata la connessione al database e impostata la query:
vogliono essere visualizzati tutti i dati disponibili per quel determinato
paziente. La connessione al database è stata effettuata tramite i driver
appositi di MySQL e tramite la creazione di una classe servlet
64
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
particolare, chiamata Database, la quale viene sempre utilizzata per
istanziare oggetti nei servlet utilizzati nelle RPC. Come salvataggio
temporaneo di tali dati vengono utilizzate delle variabili di tipo String,
una per ogni dato, cioè colonna del database. Si è scelto di utilizzare
variabili di tipo String per il semplice fatto che sono semplici nella
modellizzazione: quindi anche per dati come le date di nascita, invece di
utilizzare il tipo Date, si è scelto di operare sempre con il tipo String.
Nel blocco try viene effettuata la query e il prelevamento e
memorizzazione dei dati nelle variabili. Questa memorizzazione viene
effettuata previa opportuna condizione che il paziente esista, altrimenti
tutti i metodi di prelevamento dei dati genereranno eccezione. Le
eccezioni generate, vengono gestite dal blocco catch. Questo non vuol
dire che il metodo lato server che verrà evocato sarà onFailure() perché
come sopra detto, il problema non è stato nella connessione al servlet.
Continuando nel blocco try, si ha la costruzione dell’ArrayList, al quale
vengono aggiunte tutte le variabili, ora contenenti i dati voluti. Molto
importante è l’ordine con cui tali dati vengono memorizzati in questo
ArrayList, in quanto, nello stesso ordine devono essere recuperati dal
lato cliente nella variabile text, risultata dal cast su result.
In conclusione a questa pagina lato server, è presente anche la
chiusura del database, ovviamente nella clausola finally.
Passiamo ora a descrivere la pagina con cui i dati sopra vengono
inseriti ed anche modificati. Per effettuare queste due operazioni
abbiamo utilizzato la stessa pagina senza dover rifare graficamente due
pagine uguali: le operazioni lato server ovviamente saranno differenti.
Tale classe è stata chiamata Patient. Questa pagina è fatta diversamente
65
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
dalla precedente. Sono presenti delle label ed in più sono presenti dei
campi di inserimento testo, in cui l’utente (requester) inserisce i dati, ma
anche dove gli stessi dati vengono visualizzati e pronti per essere
modificati.
Nel costruttore sono presenti diversi parametri utili: vengono
passati la finestra in cui viene aperta questa pagina, la pagina della
cartella clinica, un parametro booleano e il pannello di tabs adibito alla
visualizzazione della pagina precedente. Molto importante è soprattutto
il parametro booleano, che a seconda se vero o falso, permette di
attivare le procedure di visualizzazione e modifica o inserimento.
Come pannello di base anche qui è stato utilizzato un
AbsolutePanel: la struttura grafica è la stessa della pagina precedente,
ovvero organizzata su due colonne per avere la pagina con un’altezza
più piccola possibile.
Le label hanno tutte lo stile delle precedenti, cioè un carattere
grassetto. Per le caselle di testo il widget utilizzato è il TextField,
mentre per i pulsanti di scelta esclusiva si è utilizzato il RadioButton.
Per quanto riguarda l’inserimento delle date, è presente un widget
apposito nelle librerie Gwt-Ext, il DateField, il quale tramite un pulsate,
permette la visualizzazione di un calendario con la possibilità di
scegliere la data che si desidera.
Affrontiamo il discorso sulla modalità di inserimento dei dati.
Questa pagina viene utilizzata in questa modalità nella sezione dedicata
al requester, presentandosi in uno dei tab. Come prima cosa si è dovuto
prendere degli accorgimenti di tipo logico. Anche se questi
accorgimenti possono sembrare banali, un lavoro ben fatto deve sempre
effettuare controlli e prevedere ogni casualità. Alcuni campi ovviamente
66
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
non possono essere vuoti e altri ancora devo rispettare alcune regole. Il
nome, il cognome e la data di nascita, non possono essere vuoti, perciò
tramite un apposito metodo setAllowBlank(false) abbiamo reso questo
impossibile.
La data di morte deve essere selezionabile, e quindi visualizzabile,
solo se è il paziente è morto effettivamente, cioè se è spuntata la voce
corrispondente. Oltre a questo la data di morte non deve essere
precedente a quella di nascita.
In questa modalità non vengono visualizzati dati al caricamento
della pagina, quindi si può passare subito a parlare della parte lato
server. Una volta inseriti i dati voluti, il requester preme il pulsante di
memorizzazione dei dati e avvia la RPC corrispondente. Qui come
prima cosa si analizza la giustezza dei dati inseriti, ovvero viene
controllato che l’eventuale data di morte sia posteriore alla data di
nascita: se questo non avviene, il fatto viene segnalato all’utente con la
marcatura in rosso della data di morte. Come al solito ora viene
istanziato il servizio e creato l’oggetto AsyncCallback ed effettuata la
chiamata lato server. In questa chiamata vengono inseriti i dati digitati
dall’utente e passati al servlet tramite i parametri del metodo specifico.
Nel servlet viene recuperato dalla sessione l’id dell’utente che sta
inserendo il paziente: questo avviene per avere traccia dei pazienti del
requester e sapere a chi appartengono. Dopo l’inserimento viene anche
recuperato l’id, assegnato automaticamente, del paziente e impostata la
sessione per questo paziente. Questo id è necessario in quanto terminata
l’azione del servlet, cioè dopo l’effettivo inserimento del paziente, viene
aperta automaticamente la cartella clinica.
67
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
Passiamo ora alla modalità di modifica dei dati. La pagina è aperta
in questa modalità tramite il menù di modifica disponibile nella toolbar
del tab di visualizzazione dei dati del paziente all’interno della cartella
clinica. In questa modalità la stessa pagina deve compiere due RPC, una
per la visualizzazione dei dati da modificare, l’altra per la modifica
degli stessi. La prima RPC avrà luogo automaticamente al caricamento
della pagina. Questa procedura avviene in modo simile alla pagina di
visualizzazione dei dati descritta nella prima parte di questa sezione: i
dati vengono memorizzati in un ArrayList come dati uscenti dal servlet
e tramite un opportuno metodo, visualizzati nelle caselle di testo, nei
campi data ecc. Questo avviene sempre sotto condizione che tali dati
non siano nulli. Il servlet non fa nient’altro che prelevare tutti i dati
disponibili per il paziente identificato dalla sessione attuale e caricarli
nell’ArrayList di output. Anche qui ricordo che l’ordine è essenziale e
deve essere rispettato lato cliente e lato server.
Per quanto riguarda invece la procedura di modifica, questa avviene
alla premuta del pulsante di memorizzazione. Come per l’inserimento,
anche qui vengono effettuati controlli relativi alla giustezza delle date
prima di proseguire. La particolarità che abbiamo in questa procedura è
che nel caso di successo della chiamata RPC vengono eseguite diverse
operazioni.Viene innanzitutto aggiornato il tab che visualizzava i dati
del profilo del paziente: questo avviene costruendone uno uguale al
precedente e sostituendo quest’ultimo al vecchio, settando ovviamente
tutti le proprietà giuste quali il titolo del tab, la grandezza ecc. Inoltre
viene anche aggiornato il nome del paziente nell’albero laterale della
cartella clinica. Al termine di tutto viene anche chiusa la finestra pop-up
che si è aperta. Il risultato alla chiusura della finestra è un
aggiornamento automatico di tutti i dati visualizzati dal paziente.
68
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
Nel servlet la procedura di modifica è molto semplice e viene
eseguita effettuando la query di modifica in base all’id attuale del
paziente, anche qui prelevato dalla sessione.
Gli unici problemi riscontrati i queste pagine sono stati relativi alle
date e al loro formato, soprattutto in fase di memorizzazione nel
database. Infatti si è dovuto utilizzare un particolare tipo di oggetto, il
SimpleDateFormat, il quale formatta la data in modo consono al
database MySQL.
5.4 Anamnesis
In questa sezione saranno presentate le soluzioni tecnologiche
utilizzate per creare le strutture riguardanti l’anamnesi del paziente.
Come prima cosa verrà evidenziata la pagina in cui viene effettuato un
elenco riassuntivo, cioè quella che viene visualizzata sul tab quando si
seleziona un nodo primario dell’anamnesi, ovvero un ramo diretto del nodo
“anamnesis” dell’albero. Questa è stata strutturata come una normale
pagina html, ovvero senza particolari accorgimenti relativi ai widget: è
presente un AbsolutePanel di base con una sola label, dove vengono
visualizzate tutte le informazioni, cioè l’elenco dei problemi o delle
patologie relative alla sezione dell’anamnesi. La visualizzazione di tali
informazioni è effettuata tramite un particolare metodo delle label, il
metodo setHtml(), che permette di impostare del codice HTML all’interno
della stessa. La nostra idea infatti è quella di visualizzare una sorta di
pagina web, con un elenco puntato di tutte i problemi, il tutto tramite i
consueti tag HTML.
69
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
Dal punto di vista del server, invece, le RPC sono abbastanza
complicate. Innanzitutto è stato necessario utilizzare una chiamata
remota per reperire dalla sessione corrente il tipo di utente, requester o
dottore. Questo è stato fatto per un motivo di semplice contorno, ma pur
sempre utile. Infatti è presente un messaggio che invita il requester, e
solamente questo, ad interagire con la barra del menù per aggiungere
nuovi problemi. Si capisce quindi che, anche se è solo una scritta, tale
non deve essere visualizzata per il dottore, per non creare confusione, in
quanto la barra citata dalla scritta non risulterebbe disponibile per il
dottore. Al successo di questa RPC, il tipo di utente viene memorizzato
in una variabile e utilizzato come parametro sulla struttura condizionale
relativa alla visualizzazione del messaggio.
L’altra RPC presente è più
complessa
e
serve
a
reperire
effettivamente l’elenco riassuntivo dei problemi. Come parametro
prende l’id del nodo selezionato, così da riconoscere di che sezione
dell’anamnesi si tratta: da questo quindi è possibile eseguire la query
esatta sul database e prelevare i dati con il solito ArrayList. Al successo
di questa chiamata non viene fatto altro che costruire il messaggio,
ovvero personalizzare la scritta, come per esempio, “ci sono 3 tipi di
allergie memorizzate”, anziché di problemi familiari; ma anche
prelevare i dati dall’ArrayList e creare l’elenco puntato. L’id sopracitato
viene prelevato quando l’utente seleziona un nodo dell’albero della
cartella clinica: tale identificativo infatti non sarà altro che il nome del
nodo selezionato, già differenziato per costruzione dell’albero stesso.
In queste pagina di visione generale, sono stati utilizzati i classici
tag HTML perché si voleva anche testare la flessibilità del GWT e
tentare di mescolare anche del puro codice HTML. Inoltre questo
70
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
metodo ci sembrava il più semplice e rapido per avere un elenco creato
dinamicamente.
5.5 Allergology
La prima sezione dell’anamnesi che si incontra è quella relative alle
allergie. Vi sono qui due classi, una necessaria per la visualizzazione in
dettaglio dei dati dell’allergia e un’altra per l’inserimento o la modifica.
Partiamo con la classe che effettua la visualizzazione dei dettagli
riguardanti la singola allergia. Come prima cosa ricordo che i dati
mostrati in questa pagina sono il nome dell’allergia, la sua data di inizio
ed eventualmente quella di fine e alcune note aggiuntive. La struttura di
questa pagina, dal lato client, risulta quindi molto semplice: una serie di
label disposte su di un AbsolutePanel. Tali label sono differenziate
come per la visualizzazione del profilo del paziente. Le label che
fungono da marcatura dell’informazione sono come al solito evidenziate
con uno stile grassetto, mentre le altre label inizialmente sono vuote e
saranno riempite dal risultato della RPC. La chiamata al server verrà
effettuata naturalmente al caricamento della pagina. Una precisazione
particolare va fatta per la visualizzazione delle note. Avendo la
possibilità di contenere diverse righe, si è scelto di adoperare una
diversa soluzione, cioè utilizzare un pannello per la visualizzazione. Un
pannello infatti ha la possibilità di avere lo scroll orizzontale e verticale
e quindi faceva esattamente al nostro caso.
Analizziamo ora il servlet che effettua la query per reperire i giusti
dati dal database. Questa query si basa sul concetto fondamentale di
poter conoscere l’id dell’allergia, cioè l’identificativo assoluto di quel
71
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
record all’interno della tabella. Questo id è ricavato dalla sessione,
opportunamente settata quando l’utente seleziona il nodo dell’allergia.
Attenzione a non confondere tale id con l’id dell’allergia: il primo è
effettivamente l’identificativo del problema allergico del paziente,
mentre il secondo è l’id del tipo di allergia. Recuperato questo id,
l’interrogazione a database è quindi molto semplice. Tramite un join si
risale al nome dell’allergia e tramite l’id si riducono i vari record ad uno
singolo. Ogni dato viene salvato in un ArrayList e ritornato al lato
client. Al successo della RPC, i dati vengono prelevati all’ArrayList ed
utilizzati per assegnare il valore alle singole label ed al pannello delle
note. Per riempire tale pannello, abbiamo trattato il dato dell’ArrayList
come del testo HTML e quindi l’apposito metodo setHtml per riempirlo.
Ora affrontiamo invece il discorso relativo all’altra pagina, ovvero
quella che permette le operazioni di inserimento e modifica delle
allergie. Si è scelto ovviamente di sviluppare queste funzionalità sulla
stessa pagina e, come per il profilo del paziente, di utilizzare un
parametro booleano per identificare in quale modalità tale pagina stia, in
quel momento, lavorando. Ricordo che ogni manipolazione di dati può
essere effettuata solamente dal requester. Questa pagina infatti viene
visualizzata tramite una finestra che viene aperta dalla barra degli
strumenti: per l’inserimento tale opzione comparirà nella pagina di
riepilogo delle allergie, mentre per la modifica la barra in questione è
visualizzata nella pagina di dettaglio descritta precedentemente.
La struttura grafica anche qui si basa su di un AbsolutePanel. I
widget inseriti sono una ComboBox necessaria per la scelta
dell’allergia, una TextArea utilizzata per l’inserimento delle note
72
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
aggiuntive ed un paio di DataField utilizzati per l’inserimento delle date
di inizio e fine allergia. Come parametri del costruttore grafico sono
passati la finestra di pop-up dove viene aperta la pagina, la cartella
clinica stessa ed il parametro che identifica la modalità di esecuzione.
Una procedura comune a tutte e due le operazioni è il caricamento
dei dati presenti sulla ComboBox: tali dati vengono prelevati dal
database tramite una normale query e memorizzati nell’oggetto Store,
che funzionerà da sorgente per la ComboBox. Tutto questo avviene al
completamento della RPC. Infatti i nomi vengono prelevati dalla tabella
delle allergie e memorizzati sull’ArrayList in uscita.
Affrontiamo per prima la situazione in cui il requester necessita di
inserite una nuova allergia. Dopo aver inserito tutti i dati voluti, viene
avviata la RPC necessaria per l’inserimento. Il servlet acquisisce tali
dati tramite i parametri, ottiene l’id del paziente tramite la sessione ed
effettua una normale query di inserimento. Questa procedura
ovviamente viene bloccata in partenza se i valori delle date non sono
logicamente validi, ovvero se la data di inizio è posteriore a quella di
fine: in tal caso, alla premuta del pulsante, la data di fine allergia viene
marcata
in
rosso
dell’inserimento
e
l’utente
vengono
avvisato
effettuate
dell’errore.
delle
Alla
operazioni
fine
necessarie
all’aggiornamento della struttura della cartella clinica: viene infatti
ricaricato l’albero per visualizzare il nodo della nuova allergia ed in più
viene anche ricaricata la pagina riassuntiva dell’allergia in modo da
poter visualizzare il completo elenco aggiornato.
Nella modalità di modifica dei dati, è come prima cosa necessaria
una RPC che carichi i dati da modificare. La chiamata che esegue tale
compito viene effettuata nello stesso metodo del servlet che carica i dati
73
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
relativi alla ComboBox. Ovviamente qui verranno caricati anche i dati
relativi all’allergia, sempre identificata dall’id contenuto nella sessione
impostata alla selezione del nodo. Alla fine di tale query, i dati vengono
inseriti nell’ArrayList. Lato client questa volta verranno recuperanti
anche i dati necessari a riempire le caselle di testo, cosa non fatta in
modalità di inserimento.
La procedura effettiva che modifica i dati viene eseguita alla
premuta del pulsante di memorizzazione: la RPC viene avviata solo se i
dati rispettano le sopracitate regole riguardanti le date. Nel servlet viene,
come prima, cosa reperito l’id dell’allergia tramite il nome della stessa,
in quanto nella tabella contenente le informazioni dell’allergia del
paziente non è presente il nome dell’allergia, ma solo l’id identificativo.
Questo id è necessario se viene modificato il nome dell’allergia. Dalla
sessione viene recuperato l’id del problema allergico da modificare e
quindi effettuata una query di aggiornamento in base a tale dato. Lato
client, al termine della chiamata, viene come prima cosa ricreato il
pannello di visualizzazione da sostituire a quello vecchio (prima pagina
descritta in questa sezione) ed infine ricaricato l’albero della cartella
clinica.
In queste pagine, non abbiamo riscontrato particolari problemi in
quanto ci siamo aiutati parecchio con l’utilizzo delle sessioni e dei
parametri. Soprattutto l’utilizzo dei parametri al costruttore rende queste
pagine molto dinamiche e con la possibilità di avviare procedure molto
complesse. Si pensi che già il fatto di dover interagire con
l’aggiornamento dell’albero o della cartella clinica stessa, senza la
possibilità di passare questi parametri, sarebbe stato estremamente
difficile e macchinoso. Una delle caratteristiche più importanti del GWT
infatti sta nello sfruttare queste tecniche derivanti dal Java, senza dover
74
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
necessariamente passare dal DOM come per il JavaScript: ricordo infatti
che come parametri è possibile passare anche un oggetto, proprio come
in Java. L’unica cosa non troppo semplice è stato il dover rendere
dinamica la ComboBox con i nomi delle allergie, anche se con l’utilizzo
dello Store abbiamo risolto ogni problema.
5.6 Familiars
Nella cartella clinica è presente una sezione riguardante i dati
medici dei genitori del paziente. Anche qui sono presenti due classi, una
per la visualizzazione ed una per l’inserimento e la modifica. Questa
parte della cartella clinica non prevede la presenza della pagina
riassuntiva delle problematiche del paziente, in quanto non necessaria:
la pagina di visualizzazione quindi viene attivata direttamente con la
selezione del nodo sull’albero, senza quindi essere previsto nessun
ulteriore nodo secondario. Se comunque non ci sono dati inseriti viene
mostrata all’utente una pagine che appunta informa che tali dati non
sono disponibili.
Alla base della pagina di visualizzazione è presente un
AbsolutePanel. Con il solito meccanismo una serie di label vengono
utilizzate per la visualizzazione dei dati provenienti dal server. Anche in
questa pagina sono presenti delle note aggiuntive inserite dal requester,
quindi abbiamo deciso di operare nella stessa maniera delle pagine
precedenti, ovvero utilizzando un pannello invece di una label. Per
questo pannello, oltre che ad uno stile apposito di formattazione del
testo, è stato impostato anche lo scroll automatico, interno alla pagina,
così da ottenere un effetto simile all’iframe dell’HTML.
75
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
I dati necessari al riempimento delle label vengono effettuati
tramite la consueta chiamata lato server. Nel servlet è presente un solo
metodo che svolge tale compito. Come prima cosa viene recuperato
l’identificativo del paziente dalla sessione aperta. Tramite questo id
viene effettuata la query, che risulta molto semplice, in quanto ogni
record di dati nella tabella coinvolta è univoco per ogni paziente. Come
al solito i dati desiderati vengono memorizzati sull’ArrayList e ritornati
al client. Il client al successo della chiamata preleva tali dati dal result
del metodo onSuccess() dell’oggetto AsyncCallback effettuando il
consueto cast ad ArrayList, ma non li utilizza direttamente. Infatti i dati
prelevati dal server non sono nel giusto formato e quindi pronti per
essere visualizzati sulle label. Oltre al solito controllo se i dati non sono
nulli, è necessaria un’ulteriore analisi. L’informazione sulla morte dei
genitori, infatti, è trattata in modo binario nel database, perciò a livello
grafico, non è fattibile visualizzare per esempio 0 per indicare che il
paziente è morto, sarebbe incomprensibile. Quindi si è scelto di
adoperare una struttura condizionale, lato client, che controlla i dati
prelevati da database e visualizza il giusto testo all’interno della label
specifica. Questo ovviamente è fatto per entrambi i genitori. Per
impostare il testo delle note ricordo che la procedura è leggermente
diversa rispetto alle label: è necessario trattare i dati come normale testo
HTML ed utilizzare il metodo specifico dei pannelli setHtml().
Passiamo ora alla pagina e alle classi lato server e client che
permettono di inserire e modificare i dati relativi ai genitori del
paziente. Bisogna innanzitutto far capire il meccanismo con cui tale
pagina viene caricata. La modalità di inserimento dei dati viene attivata
solo se non vi sono già dati presenti, in quanto come detto ogni record
in tabella è univoco per ogni paziente. La modalità di modifica invece è
76
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
disponibile solo se ci sono già dei dati. Tutto questo viene deciso nella
classe che rappresenta la cartella clinica nel suo insieme: non viene fatto
altro che impostare la variabile booleana di flag necessaria a distinguere
le due modalità.
Nel costruttore grafico vengono quindi passati la finestra pop-up in
cui tale pagina viene visualizzata, la cartella clinica stessa e appunto il
parametro booleano. Graficamente la pagina è basata sul solito
AbsolutePanel che contiene diversi widget. Come prima cosa è presente
un widget non ancora trattato, ma che risulta essere graficamente molto
efficace, il FieldSet. Tale widget si comporta come un pannello ed è
utilizzato per raggruppare altri widget con lo stesso nesso logico. I
widget contenuti in questo pannello sono contornati e quindi
raggruppati, così da fornire un effetto grafico che, apparentemente non
sembra importante, ma che in realtà per chi utilizzerà il portale risulterà
molto significativo. Tale widget è stato utilizzato molto spesso nelle
diverse classi.
Gli altri widget presenti sono ComboBox, CheckBox e una
TextArea. Le checkbox in questa pagina non sono caricate con dati
provenienti da database, infatti, rappresentando i vari gruppi sanguigni,
non sono previste possibilità di ampliamento o modifica. I gruppi
sanguigni sono caricati tramite un Store e l’associato oggetto
SimpleStore, che preleva appunto il testo necessario da un metodo
contenuto in questa classe: i dati sono passati trami array
multidimensionale, in quanto tale oggetto acquisisce solo questa
tipologia di variabili. Sempre riguardanti le ComboBox, sono
interessanti le varie proprietà impostate: oltre allo store, è stato
necessario
settare
due
proprietà,
setForceSelection(true)
e
setSelectOnFocus(true). La prima per restringere la scelta del testo alla
77
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
lista degli elementi nella combobox e non permettere all’utente di
inserire “nuovi gruppi sanguigni”. La seconda è stata utilizzata per
permettere un’automatica selezione di uno delle voci in elenco quando
si comincia a scrivere nella combobox (autocompletamento).
Procediamo con l’analisi della pagina in modalità inserimento. In
questa modalità il valore del flag booleano sarà false. L’inserimento
quindi non prevede nessun tipo di interazione con il server al
caricamento della pagina. La procedura di attivazione della RPC
avviene tramite la premuta di pulsante di memorizzazione: a differenza
di altre pagine, qui i dati inseriti dal requester non sono soggetti a
nessun controllo logico in quanto si tratta di dati non dipendenti.
Prima dell’attivazione della chiamata vera e propria, i dati prelevati
dai vari widget devono essere correttamente formattati. Infatti, come
detto sopra, i dati nel database non sono memorizzati come vengono
inseriti dall’utente. Una struttura condizionale ha il compito di “capire”
se la checkbox relativa alla morte dei genitori è selezionata o meno e
quindi memorizzare a 0 oppure 1 (0=morta, 1=viva) la variabile che
verrà passata come parametro nella RPC.
Nel servlet, acquisiti i dati dal client, avviene la query di
inserimento: prelevato l’identificativo del paziente dalla sessione, tutti i
dati sono ora nel giusto formato e quindi memorizzabili correttamente.
La pagina in modalità modifica funziona in modo differente. Al
caricamento vengono visualizzati i dati che l’utente ha richiesto di
modificare. Tale procedura viene effettuata solamente in questa
modalità. Effettuata la chiamata al servlet, non sono necessari parametri
e viene eseguita una query sull’id del paziente ottenuto dalla sessione. I
dati vengono quindi prelevati dal database, senza alcuna formattazione,
78
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
e memorizzati nell’ArrayList. Solamente quando il controllo ritorna al
lato client i dati vengono formattati correttamente così da poter essere
visualizzati: le checkbox vengono selezionate solo se dal database il
dato sarà 1, ovvero genitore ancora vivo.
Quando i dati vengono modificati dal requester e viene premuto il
pulsante di memorizzazione, viene avviata la chiamata lato server
relativa alla modifica. La formattazione corretta dei dati avviene lato
client: i dati pronti da inserire nel database sono quindi passati come
parametri dello specifico metodo del servlet. Qui la query di
aggiornamento viene eseguita sull’identificativo del paziente prelevato
dalla sessione, in quanto esso è univoco per ogni record. Quando
termina l’azione del servlet e si passa al metodo onSuccess() del lato
client, sono necessarie diverse operazioni di aggiornamento della
struttura della cartella clinica. Viene innanzitutto ricreato un tab identico
a quello in cui venivano visualizzati i dati, cioè con le stesse proprietà e
caratteristiche. Nella cartella clinica inoltre è necessario aggiornare i
due tab togliendo quello vecchio e sostituendovi quello appena creato,
nonché ricaricare l’albero dinamico. Queste operazioni avvengono
grazie alla cartella clinica che è stata passata come parametro al
costruttore della classe: vengono attivati due metodi della cartella
clinica, uno per lo scambio dei tab, l’altro per l’aggiornamento
dell’albero.
Non ci sono stati particolari problemi nel realizzare questa sezione,
in quanto anche la formattazione dei dati necessaria per la
visualizzazione è stata relativamente semplice.
79
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
5.7 Family Pathologies
In questa sezione verranno prese sotto esame le soluzioni
tecnologiche utilizzate per gestire le patologie dei parenti. Sono qui
presenti due pagine, una per la visualizzazione dei dettagli ed una con il
compito di fornire la possibilità di inserire o modificare i dati.
La pagina di visualizzazione viene mostrata quando si accede al
nodo della patologia. Le informazioni presenti sono il nome della
patologia, seguita da un elenco dei parenti in cui questa è stata
riscontrata. Come pannello di base è stato utilizzato il solito
AbsolutePanel. Il fatto che sia stato utilizzato quasi sempre
l’AbsolutePanel è dovuto al fatto che la struttura grafica delle pagine
nella cartella clinica sono molto simili. Inoltre si è cercato di dare una
sorta di conformità tra le varie pagine. Il nome della patologia viene
visualizzato su di una label, mentre l’elenco dei parenti su di un
pannello, sempre per permettere lo scorrimento. Le proprietà delle label
sono sempre le stesse, cioè carattere grassetto per le etichette di
marcatura e normale per quelle di visualizzazione dei dati dinamici. Il
pannello ovviamente ha impostata la proprietà dello scorrimento
automatico in caso di presenza nell’elenco di molti parenti.
La chiamata RPC viene eseguita al caricamento della pagina stessa.
La query che viene effettuata dal servlet necessita di due cose: un
identificativo del record da mostrare e ovviamente, come per le allergie,
di reperire il nome della patologia, essendo in un'altra tabella. L’id viene
prelevato come al solito dalla sessione corrente: quando viene
selezionato il nodo della corrispondente patologia familiare, viene anche
settato il giusto id nella sessione, tutto nella cartella clinica. Per quanto
riguarda il nome della patologia, basta effettuare un join tra tabelle ed
80
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
otteniamo il risultato voluto. I dati vengono caricati nell’ArrayList e
pronti per essere utilizzati lato client. Bisogna però ricordare che i dati
presenti nel database e quindi ora memorizzati nell’ArrayList sono in
formato binario, ovvero se è certificato il riscontro della patologia per
quel parente nel database sarà presente 1, in caso contrario 0. Come si
potrà capire tali dati dovranno essere formattati a dovere lato client.
Ritornando lato client, quando la RPC ha avuto successo, i dati
cominciano ad essere prelevati dall’ArrayList e formattati. Come
visualizzazione si è scelto di utilizzare un elenco puntato, creato con i
classici tag HTML. Questo è stato possibile grazie all’utilizzo del
pannello e del suo metodo setHTML(). Con tale metodo è possibile
costruire anche un’intera pagina HTML, passando come parametro la
stringa contenente il codice HTML desiderato.
Per ogni dato contenuto nell’ArrayList verrà notificata in una
variabile di appoggio la presenza o meno di quel parente: in realtà,
questa variabile conterrà il codice HTML necessario per tale metodo e
quindi in essa verrà accodato il messaggio uscente, direttamente con il
tag <li> impostato per ogni parente. Il tutto è effettuato da varie
strutture condizionali che oltre a controllare la presenza o meno del dato
nell’ArrayList, controllano anche il numero binario contenuto in esso e
quindi decidono se accodare il messaggio alla variabile di appoggio
oppure no.
Per quanto riguarda la visualizzazione vera e propria le varie
proprietà quali il padding e gli stili sono quindi forniti direttamente dal
codice HTML stesso.
81
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
Passiamo ora a parlare della pagina di inserimento e modifica dei
dati. Anche qui, come negli altri casi, si è cercato di raggruppare queste
due funzioni, così da ottenere lo stesso risultato da un’unica pagina o
classe. Ovviamente sarà presente un parametro che notifica quale
funzione deve essere attivata: per la precisione abbiamo utilizzato un
parametro booleano passato al costruttore della classe, il quale assume
valore vero in caso di modifica e falso in caso di inserimento di nuovi
dati. Questo parametro, viene passato al costruttore grafico e quindi
impostato all’atto della creazione dell’oggetto e quindi della pagina.
Oltre a questo parametro, nel costruttore sono passati anche la finestra
di pop-up dove vengono aperte le pagine e la cartella clinica stessa.
L’attivazione delle due modalità avviene tramite la toolbar presente
nei tabs di visualizzazione: la pagina verrà impostata per l’inserimento
se il requester accederà alla barra degli strumenti dalla pagina di
riepilogo, mentre sarà attivata la modifica solamente dalla barra
presente nel dettaglio della patologia desiderata.
Graficamente tale pagina è semplicemente costituita da una
ComboBox, che permette la selezione della patologia; e da un elenco di
tutti i parenti, selezionabili tramite dei pulsanti di scelta multipla.
Entrambe appoggiano su di un AbsolutePanel.
I dati nella ComboBox sono reperiti da database, sia nella modalità
di inserimento che in quella di modifica. Questo è stato fatto perché si
vuole rendere dinamica il più possibile la pagina: così facendo, la
modifica o aggiunta di una patologia è molto più semplice ed avviene
senza dover modificare direttamente il codice della classe. Questa
procedura remota avviene tramite una RPC al caricamento della pagina.
Dal servlet vengono reperiti i nomi delle patologie, disposte in ordine
82
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
alfabetico ed infine memorizzate sull’ArrayList. Quando il controllo
ritorna lato client, avviene al vera e propria costruzione, non solo della
ComboBox, ma anche dell’intera pagina. I dati appena prelevati dal
servlet vengono memorizzati nello store, il quale servirà a caricarli nella
ComboBox. Come detto, dopo aver caricato i dati sulla ComboBox,
avviene anche la vera e propria creazione della pagina, tutto all’interno
del metodo onSuccess(). La creazione del pannello contenente l’elenco
dei parenti è stato effettuato con una procedura abbastanza complessa.
In realtà, infatti, questo pannello non è presente direttamente in questa
classe, ma è costruito all’interno di una seconda classe. Oltre alla
semplice creazione della pagina grafica tramite un AbsolutePanel ed una
griglia con la possibilità di scelta multipla, vi sono presenti due metodi
per la memorizzazione e il recupero dei dati da questa griglia. Questa
classe è stata necessaria per prima cosa perché la struttura della griglia
in questione è abbastanza complessa e poi in quanto permetteva una
maggiore separazione delle due modalità: infatti basta attivare dalla
pagina genitrice il metodo desiderato e possiamo o memorizzare o
ottenere i valori richiesti.
Ritornando alla classe principale, per ottenere la griglia sopra citata,
non basta far altro che creare un oggetto della seconda classe, avendo
quindi a disposizione tutti i suoi metodi. Fatto questo si aggiunge
l’oggetto appena creato ad un Panel. Dopo la creazione di questo
pannello, a seconda in quale modalità la pagina sta operando, vengono
create due strutture differenti: in entrambe è presente un pulsante per la
memorizzazione, mentre per la modalità di modifica, è stato introdotto
anche un pulsante per reimpostare i dati iniziali.
Analizziamo come primo caso l’intervento della pagina in modalità
inserimento. Oltre al caricamento dei dati nella ComboBox, al
83
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
caricamento della pagina non vengono effettuare altre chiamate remote
ai servlet. Il requester prima di effettuare la memorizzazione dei dati,
deve rispettare alcune regole impostate. In questa fase, la selezione di
una patologia è necessariamente obbligatoria e non è possibile inserire
tramite questa form un’eventuale nuova patologia: il requester deve
quindi selezionare una delle patologie dall’elenco presente nella
ComboBox. Inoltre è necessario, come ovvio, anche la selezione di uno
dei parenti, per dare un senso all’inserimento stesso. Il non rispettare tali
regole, invalida la procedura di inserimento, segnalando il problema
all’utente. Inseriti correttamente i dati, si attiva la procedura remota
premendo sul pulsante di memorizzazione.
La prima cosa che viene effettuata è quella di prelevare i dati dalla
griglia ed inviarli come parametro al servlet. Questi dati sono passati
tramite un array di interi, così sono già ben formattati per il database.
Oltre a questo array è passato ovviamente anche il nome della patologia.
Segnalo inoltre che, anche se non sempre enunciato, come ultimo
parametro
di
ogni
chiamata
remota
è
necessario
l’oggetto
AsyncCallback.
Per effettuare l’inserimento, oltre alla forma binaria dei parenti che
notifica la presenza o assenza della patologia, è necessario reperire l’id
del paziente e della patologia stessa. L’identificativo del paziente viene
recuperato come al solito dalla sessione corrente. Successivamente
viene reperito l’identificativo del nome della patologia dalla tabella da
cui venivano anche reperiti i dati da caricare nella ComboBox. Ottenuti
i dati necessari si procede con la query di inserimento.
Nel client, completata l’azione del servlet, vengono utilizzati i
parametri passati al costruttore. Con la cartella clinica viene prima
84
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
ricaricato l’albero così da avere la nuova patologia inserita.
Successivamente si procede con la ricarica della pagina di riepilogo,
così da far comparire il nome del problema inserito. Infine con il
parametro della finestra non viene fatto altro che invocare il metodo di
chiusura della stessa.
Affrontiamo ora un discorso analogo per la procedura di modifica.
Qui al caricamento, oltre alla chiamata remota necessaria per la
visualizzazione dell’elenco di patologie, è effettuata anche la RPC per
reperire i dati da modificare. Questa procedura non farà nient’altro che
selezionare la giusta patologia dalla ComboBox e selezionare i relativi
parenti che ne sono affetti.
Nel metodo del servlet disposto per tale operazione come prima
cosa viene reperito l’identificativo univoco del record da visualizzare:
questo è possibile in quanto tale parametro è impostato dalla cartella
clinica alla selezione del nodo desiderato ed è quindi recuperabile dalla
sessione corrente. Il nome della patologia, che non è inserito nella stessa
tabella dei dati del paziente, viene prelevato tramite un semplice join. I
dati relativi alla presenza dei parenti vengono caricati su di un
ArrayList, ed uniti in un secondo ArrayList già contenente il nome della
patologia prima prelevato.
Lato client le informazioni del servlet vengono interpretate da una
struttura iterativa: il ciclo scorre l’ArrayList, separando il nome dalle
presenze dei parenti. Successivamente i dati sui parenti vengono caricati
e visualizzati sulla griglia. Questa procedura è richiamata anche dal
pulsante, sopra citato, che permette il recupero delle informazioni
iniziali dove infatti non viene fatto altro che ricaricare virtualmente la
pagina.
85
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
La modifica dei dati appena visualizzati avviene anche qui tramite
il tasto di memorizzazione. Prima di avviare la RPC tramite l’apposito
metodo, vengono prelevati i parenti selezionati ed inseriti nell’array di
interi così da avere già una forma binaria (come nell’inserimento). La
RPC viene quindi eseguita e come parametri vengono passati proprio il
nome della patologia e questo array di interi. Ovviamente anche qui
viene effettuato un controllo sui dati inseriti, proprio gli stessi controlli
che avvenivano in fase di inserimento; in caso contrario i la RPC non
viene eseguita.
Lato servlet vengono reperiti i dati ulteriori necessari alla query:
dalla sessione viene prelevato l’identificativo del record di dati da
modificare, mentre tramite un’ulteriore query viene ricavato l’id della
patologia. La query di modifica è eseguita sulla base dell’id del record,
in quanto chiave univoca nella tabella.
Quando si ritorna al lato client, vengono eseguite le consuete
operazioni di routine: aggiornamento dell’albero e del tab di
visualizzazione corrente. Per l’albero basta utilizzare il consueto metodo
prelevato dalla cartella clinica, che era stata opportunamente passata al
come parametro nel costruttore del Composite. Per l’aggiornamento del
tab invece si è operato come per gli altri casi simili: si è dapprima
ricreato un tab identico, per proprietà e caratteristiche, a quello
visualizzante i vecchi dati modificati, e successivamente si è utilizzato il
metodo di scambio tabs della cartella clinica. Infine è presente anche
l’operazione di chiusa automatica della finestra alla fine dell’operazione
di modifica.
86
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
Nello sviluppo e realizzazione di queste classi non abbiamo
riscontrato parecchi problemi, se non nel dover creare una classe in più
per la manipolazione della griglia dei parenti. Abbiamo comunque
scelto questa soluzione perché ci è sembrata la più semplice e ordinata
da un punto dal punto di vista del riutilizzo, anche se a prima vista può
sembrare il contrario. Anche in questo caso, tramite il passaggio dei
parametri, non è stato necessario accedere direttamente al DOM. Per il
resto la risoluzione è stata molto simile che per la sezione delle allergie.
5.8 Pathologicals
In questo paragrafo verranno presentate le soluzione utilizzate in
quella sezione della cartella clinica che riguarda le patologie contratte
dal paziente in esame. Vi è la presenza anche qui di due pagine, una atta
a presentare i dettagli della patologia selezionata, l’altra a fornire
funzionalità manipolative quali l’inserimento o la modifica di queste
informazioni.
Per accedere alla pagina dei dettagli bisogna selezionare la
patologia dall’albero laterale presente nella cartella clinica. La struttura
grafica che accompagna questa pagina è simile a quelle precedenti,
ovvero ha come base un AbsolutePanel e le solite soluzione di stile da
applicare alle label. Le informazioni presenti sono molteplici e
comprendono oltre che alla patologia, anche informazioni riguardo
l’eventuale ospedale dove è avvenuto il ricovero, visualizzando anche la
diagnosi e le note relative alle dimissioni. Proprio riguardo alla
visualizzazione di questi due ultime informazioni, è stato necessario
inserire nella pagina due pannelli, così da dotare le singole note di uno
scorrimento interno quando vi è bisogno. Le pagine infatti contenute
87
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
nella cartella clinica non devono essere troppo lunghe, in quanto come
ricordo la cartella clinica è aperta su di una finestra di pop-up e quindi la
sua dimensione è relativamente ridotta. Per questo pur dotando i tab di
scroll automatico, si è deciso di non appesantire la struttura creando
pagine troppo grandi.
Il riempimento delle label con i dati viene effettuato tramite una
RPC al caricamento della pagina. Questa sarà anche l’unica chiamata
remota in questa pagina. Lato server è necessaria una query che
reperisca tutte le informazioni necessarie, come il nome della patologia,
l’età, l’eventuale ricovero e le date di entrata e uscita dall’ospedale,
nonché la diagnosi e la lettera di dimissioni, ecc.. Per ottenere tali dati
come prima cosa è stato necessario ricavare l’identificativo del record di
dati. Questo parametro può essere prelevato dalla sessione corrente:
selezionato il nodo dell’albero da cui si accede alla pagina, si imposta
automaticamente tale valore. Il nome della patologia viene prelevato
tramite un join tra tabelle del database ed effettuata la query i dati
vengono memorizzati nel solito ArrayList di ritorno al lato client.
Ricordo che, parlando di diversi dati, bisogna prestare particolare
attenzione all’ordine in cui gli stessi sono memorizzati, così da essere
bene recuperati dal client.
Il client non fa altro che elaborare tali dati e dove necessario
formattarli correttamente per la visualizzazione. Innanzitutto vengono
prelevati solamente i dati presenti, ovvero viene effettuato un controllo
sull’effettiva presenza: in caso di assenza di un dato si passa al dato
successivo lasciando la label vuota. La formattazione è necessaria per il
solo campo riguardante il ricovero in ospedale. Infatti tale dato è
memorizzato in forma binaria (necessità di ricovero oppure no) e perciò
è stato sufficiente introdurre una struttura condizionale che, controllato
88
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
il valore binario, impostasse in formato “umano” il dato nella label:
viene semplicemente visualizzata la scritta “yes” o “no” a seconda se è
avvenuto o meno il ricovero. Ricordo inoltre che per i pannelli, i dati
non vengono inseriti come per le labe, ma vengono trattati come dati
HTML puri.
Passiamo ora ad affrontare la pagina che permette al requester di
manipolare i dati sopra elencati, ovvero di effettuare operazioni di
inserimento e di modifica. La scelta della modalità in cui la pagina deve
operare è scelta in base al valore di un parametro booleano, passato
direttamente quando viene creato il composite: anche qui quando il
valore sarà vero la pagina opererà in modifica, altrimenti in inserimento.
Oltre a questo parametro, sono presenti al solito la cartella clinica e la
finestra di pop-up.
La modalità di inserimento come al solito è attivabile dalla pagina
riassuntiva della sezione delle patologie, mediante la toolbar e
l’opportuno menu. Rispettivamente la modalità di modifica è attivabile
dalla pagina dettaglio descritta precedentemente in questo paragrafo.
Graficamente la pagina si sviluppa su di un AbsolutePanel
contenete altri due particolari pannelli, già incontrati: i FieldSet. Il
primo FieldSet contiene una ComboBox per la visualizzazione della
patologia ed un campo di inserimento numerico per l’inserimento
del’età di riscontro della stessa. Nel secondo FieldSet invece sono
presenti le caselle di inserimento dei dati riguardanti il ricovero
ospedaliero, quali le date di entrata e uscita dall’ospedale, la diagnosi, la
lettera di dimissioni ed ulteriori dati sull’ospedale. Quest’ultimo
FieldSet ha una particolarità: è presente infatti una checkbox laterale,
89
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
che se selezionata, permette di visualizzare i sui widgets interni,
altrimenti rimangono invisibili. Si ottiene quindi un effetto a comparsa
che mira a far inserire i dati relativi al ricovero, solo se questo è
effettivamente avvenuto.
Come per la classe delle allergie, anche qui il caricamento dei dati
della ComboBox è comune a tutte e due le modalità e viene effettuata al
caricamento della pagina. Nel servlet vengono reperiti i nomi da una
semplice query e successivamente inseriti nell’ArrayList di ritorno al
client. Nel client, tramite l’oggetto SimpleStore, vengono caricati nella
ComboBox. L’unica accortezza che si è dovuto prendere in questo caso
è quella del dover, in caso di inserimento, prelevare solamente tale
informazione dall’ArrayList: infatti lo stesso ArrayList è utilizzato per
memorizzare i dati necessari alla fase di mofica. Questo problema è
stato semplicemente affrontato con una struttura condizionale che
riconosce la modalità operativa della pagina.
Parliamo ora della pagina predisposta per la funzionalità di
inserimento dei dati. Anche qui sono presenti degli accorgimenti logici
che l’utente deve rispettare per attivare la procedura di inserimento. La
prima regola riguarda la necessaria presenza di una patologia inserita e
selezionabile solamente da quelle in elenco. L’altro accorgimento
riguarda l’inserimento della data di uscita dall’ospedale in caso di
ricovero: tale data ovviamente deve essere posteriore a quella di
ingresso. Prima dell’inserimento inoltre vengono anche reperiti i dati
relativi al ricovero solamente se questo è selezionato dal FieldSet,
altrimenti tali dati vengono passati come nulli. Rispettando tali regole
viene quindi effettuata la chiamata.
90
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
Nel servlet vengono dapprima ricavati gli ulteriori dati necessari ad
un corretto inserimento e dalla sessione viene prelevato l’id del
paziente. Tramite un query viene prelevato l’id della patologia dalla
rispettiva tabella. I dati relativi alle date vengono debitamente formattati
e quindi può avere luogo la query di inserimento.
Quando l’azione torna lato client, avvengono le varie operazioni di
aggiornamento della cartella clinica, ovvero la ricarica dell’albero
laterale e della pagina di riepilogo della sezione, oltre che la chiusura
della finestra di pop-up.
Passiamo ora all’operazione di modifica che può essere effettuata
da questa pagina. Come accennato precedentemente, qui è necessario
anche un recupero, tramite la stessa RPC di caricamento della
ComboBox, dei dati da modificare. I dati prelevati sono presenti infatti
sullo stesso ArrayList e vengono visualizzati sui rispettivi widgets.
Modificati tali dati, il requester attiva la proceduta di modifica e al
relativa chiamata remota tramite il pulsante di memorizzazione. Prima
di essere passati al servlet i dati vengono opportunamente controllati,
con gli stessi criteri che per l’inserimento.
La query lato server necessita, oltre che dei dati passati tramite
parametri, anche dell’id del record da modificare e dell’id della
patologia. Quest’ultimo è ricavato, come per l’inserimento, tramite una
query sul nome nell’opportuna tabella, mentre l’identificativo del record
è prelevato dalla sessione corrente. Una volta disponibili tutti i dati è
semplice effettuare la query di aggiornamento tramite l’identificativo
record, che è ovviamente attributo chiave.
91
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
Nel procede allo sviluppo e alla realizzazione di questa sezione, non
sono stati riscontrati particolari problemi. Le soluzioni utilizzate sono
pertanto
risultate
molto
simili
che
per
le
sezioni
illustrate
precedentemente.
5.9 Physiologicals
In questo paragrafo verrà presa in esame la sezione relativa ai
problemi fisiologici del paziente. Prima sarà descritta la pagina di
visualizzazione riassuntiva, successivamente quella che premette
l’inserimento e la modifica dei dati. In questa sezione infatti non sono
previste pagine per dettagliare ulteriormente il problema clinico, in
quanto saranno solamente visualizzate delle note generiche.
La pagina di visualizzazione è basata su di un AbsolutePanel. La
pagina che si presenta davanti all’utente è una struttura molto semplice,
con delle etichette e dei pannelli affiancati a queste. La decisione
riguardo ai pannelli è stata necessaria, in quanto le informazioni
visualizzabili sono poste sotto forma di note, senza ulteriore
formattazione, quindi la loro lunghezza è a discrezione del requester.
Con l’utilizzo di pannelli infatti possiamo sfruttare la proprietà di
scorrimento, non disponibile nelle label.
In questa pagina è presente una sola chiamata remota, necessaria al
caricamento dei dati sui pannelli. Nel servlet viene effettuata una
semplice query sull’id prelevato del paziente prelevato da sessione. Le
informazioni vengono quindi inserite in un ArrayList e ritornate al
client, senza nessun tipo di formattazione.
92
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
Lato client, i dati vengono ripresi dall’ArrayList ed utilizzati,
tramite una struttura condizionale ed interativa, per riempire i vari
pannelli. Il metodo utilizzato imposta tali dati come dati HTML, non
come normali stringhe. Questo comunque non ha complicato la
visualizzazione. Ogni pannello viene ovviamente riempito solamente in
caso di dato rispettivamente trovato nel database.
Analizziamo ora la pagina che permette l’inserimento e la modifica
dei dati visualizzati. La modalità di inserimento viene attivata tramite la
toolbar presente nel tab solamente nel caso in cui nel database non vi
siano già tali informazioni per il paziente in esame. In caso contrario è
attivata la pagina in modalità di modifica. Il controllo viene effettuato a
livello di cartella clinica generale, non in questa pagina, in quanto il
menù della toolbar è creato in quella classe.
La modalità viene decisa anche qui dal valore assegnato ad una
variabile booleana, presente tra i parametri del costruttore. Oltre a
questo parametro, sono passati anche la cartella clinica e la finestra di
pop-up.
Come widget sono stati utilizzati delle TextArea e due ComboBox,
disposti su di un AbsolutePanel. Le ComboBox non necessitano di
reperire dati dal database, in quanto visualizzano i gruppi sanguigni: si è
utilizzato uno Store che preleva i gruppi da un metodo della classe.
Partiamo con la pagina in modalità inserimento. Non vi è alcun
controllo sui dati inseriti dal requester, in quanto non sono correlati tra
loro. Ovviamente la contraddizione logica di alcune informazioni
contenuti su questa pagina, non può essere affrontata a livello di
programmazione.
93
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
Inseriti i dati quindi si avvia la procedura remota, che richiede la
presenza del servlet. In questo servlet, una volta acquisiti i valori per
passaggio dei parametri, viene eseguita una query di inserimento in base
all’identificativo del paziente, prelevato dalla sessione.
Nel ritorno al lato client, vengono eseguite le solite operazioni di
aggiornamento della cartella clinica: ricarica dell’albero e della pagina
nel tab sottostante al pop-up.
Nella modalità di modifica, invece, la prima cosa che viene
effettuata è la RPC necessaria a reperire i dati interessati. Al
caricamento viene richiamato il servlet, che tramite una semplice query
sull’id del paziente, preleva le informazioni. Nel client tali dati non
subiscono formattazione e vengono quindi prelevati dall’ArrayList e
visualizzati direttamente nelle TextArea.
La vera procedura di modifica viene richiamata quando il requester
necessita di memorizzare i dati e, alla premuta del pulsante, la chiamata
remota avvia il servlet. La query qui presente, prelevato l’id del
paziente, si appresta ad eseguire un aggiornamento con i dati passati
come parametri al metodo. Lato client le operazioni di aggiornamento
della cartella clinica sono le stesse che per l’inserimento. Quest’ultima
situazione avviene perché le due modalità vengono attivate dal
medesimo tab e differiscono solo in base alla presenza/assenza di
informazioni nel database. Nelle altre pagine ogni modalità veniva
attivata da un tab differente.
Nell’affrontare questa sezione non ci sono stati problemi di alcun
tipo, in quanto sia lato client che lato server si avevano diverse
soluzioni. Si è scelto di operare nella maniera sopra descritta perché
94
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
rappresenta la più semplice ed immediata, non complicando inutilmente
la realizzazione.
5.10 Patient Clinical Problem
In questa sezione della cartella clinica vengono analizzati i
problemi clinici del paziente. A differenza delle parti sopra descritte qui
è non è stato possibile utilizzare la stessa classe per il dottore e per il
requester. Si è adottata comunque una solida conformità grafica per
abituare così l’utente ad avere la stessa interfaccia. Le due soluzioni
differiscono notevolmente nelle funzionalità. Le operazioni del dottore
sono relative alla messaggistica ed alla refertazione del problema
clinico. Le possibilità del requester invece coinvolgono, oltre alla
messaggistica, anche l’inserimento del problema clinico stesso, nonché
la conseguente aggiunta dell’esame clinico. L’attivazione della pagina
avviene tramite la selezione dell’ultimo nodo dell’albero presente
lateralmente: al click viene visualizzata all’interno di un tab.
Verranno per prime prese in esame le soluzioni riguardanti la
sezione del dottore. Graficamente la pagina si appoggia su di un
AbsolutePanel e si sviluppa poi su due pannelli separati. Superiormente
è presente una griglia che presenta i vari problemi clinici per quel
paziente, nonché informazioni come le date di apertura e chiusura
dell’evento e il numero di esami, referti e messaggi presenti. Per una
migliore lettura è presente un raggruppamento per stato dell’evento,
ovvero “open” ecc. Nella parte inferiore invece sono presenti le schede
visualizzanti le informazioni dell’esame selezionato.
95
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
La parte inferiore è visualizzata grazie alla creazione di un oggetto
di un'altra classe. La classe relativa ai problemi clinici infatti conterrà
solamente la citata griglia, mentre le altre sezioni visualizzate sono di
altre classi Java. Desta importanza però il metodo che effettua
l’aggiornamento della griglia. Questo è necessario in caso di modifica
dello stato del problema clinico, nonché dei dati del paziente stesso. Per
questo motivo il metodo richiama tramite una procedura remota i dati
necessari alla creazione della griglia. Nel servlet quindi, vengono
recuperati i nuovi dati dal database, che è stato aggiornato, e nel client
tali vengono utilizzati alla rigenerazione della griglia stessa.
A separare le due parti è presente una toolbar con le opzioni
disponibili per il dottore. Per le opzioni riguardate i referti ed i
messaggi, la procedura richiama una classe diversa. Per l’inserimento di
messaggi o referti la classe che compie tale operazione visualizza un
form di inserimento dati: le informazioni sensibili sono il nome del
dottore, le informazioni sull’esame in questione e naturalmente il testo
inserito. La chiamata remota lato server effettua semplicemente una
query di inserimento prelevando l’id del dottore dalla sessione di login.
Importante ricordare che, nel caso di inserimento di un referto, viene
anche impostato lo stato a “reported”. Per la visualizzazione il
funzionamento coinvolge una classe diversa: viene visualizzata
l’informazione reperita, tramite la RPC, nel widget Panel. I dati
ovviamente saranno quelli inseriti al passo precedentemente.
Viene analizzata ora la parte contenente i dati relativi al problema
clinico, ovvero quella che permette la giusta selezione delle schede. Le
funzionalità qui descritte sono ricavate dalla creazione di un oggetto di
una classe differente. In questa seconda classe avverrà la vera e propria
creazione delle schede annunciate. Tramite una ComboBox come prima
96
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
cosa viene selezionato l’esame clinico che si desidera osservare. I dati
caricati sono quelli prelevati tramite una RPC da database perché
vengono visualizzati solamente gli esami realmente fatti.
Selezionato un esame viene aperto una scheda (pannello) in cui
vengono mostrate ulteriori informazioni inserite dal requester. È qui
anche possibile effettuare il download del file rispettivo. Naturalmente i
dati presenti vengono tutti prelevati da database ed identificati tramite il
parametro passato alla chiamata remota ed ottenuto dalla griglia: il
client non fa altro che formattare i vari dati nelle apposite label. Per
quanto riguarda il download la procedura è molto semplice, in quanto è
necessario solamente effettuare l’apertura del file tramite una nuova
finestra del browser. Il resto del compito è svolto dal browser.
Verrà ora presentata la parte relativa al requester. Come già
annunciato la disposizione grafica degli elementi è simile. Nella parte
superiore è presente una griglia con i vari problemi clinici del paziente,
mentre al di sotto sono presenti le solite schede. Tra le due vi è la solita
toolbar, con le opzioni disponibili per il requester. Tuttavia queste
opzioni e le sottostanti schede sono molto differenti rispetto a quelle del
dottore, causa per cui è stato necessario sviluppare due pagine separate
anziché una singola come negli altri casi.
La griglia come al solito è creata a partire da una chiamata remota
che preleva i dati necessari dal database. La query effettuata nel servlet
è molto semplice in quanto sfrutta l’id del paziente presente nella
sessione corrente, così da avere tutti i dati necessari. Le informazioni
presenti nella griglia sono lo stato del problema, le date di apertura ed
97
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
eventuale chiusura del problema, il numero di referti o messaggi,
nonché di esami effettuati.
Nella toolbar sono presenti le seguenti opzioni: impostare lo stato
del problema a “close” oppure a “request another”, visualizzarne i
dettagli oppure aggiungervi un esame, nonché creare da zero un nuovo
problema clinico. Tutte queste operazioni sono create nello stesso modo
in cui lo erano quelle del dottore.
Per le prime due operazioni non è viene fatto altro che attivare una
RPC che tramite una query di aggiornamento cambio lo stato del
problema clinico. Naturalmente al termine della chiamata remota la
griglia viene rigenerata così da includere l’aggiornamento.
Tramite le operazioni successive vengono aperte le citate schede.
Queste non sono nient’altro che dei Panel in cui l’oggetto Java creato
viene aggiunto. Per l’operazione di visualizzazione del dettaglio
dell’esame clinico sono state adottate le comuni soluzioni delle label
con i dati prelevati da database tramite una semplice RPC. L’operazione
di aggiunta di un esame o di un nuovo problema clinico sono in realtà
creati in modo speculare. Infatti lo stesso oggetto Java sta alla base di
queste due funzionalità: un form di inserimento costituito da una serie di
TextArea e con la possibilità finale di aggiungere anche il file
dell’esame di laboratorio. Come si può facilmente intuire l’inserimento
risulta molto semplice e viene effettuato trami una chiamata remota con
una query di inserimento nelle giuste tabelle del database. Anche qui a
fine di ogni RPC è necessario rigenerare la griglia.
Un particolare passaggio da affrontare invece necessita l’upload del
file sul server. Vengono utilizzati due widgets finora mai incontrati,
ovvero File Upload e FormPanel. Il primo come si capisce è utilizzato
98
Capitolo
5
–
Soluzioni
Tecniche
Cartella
Clinica
per aprire una finestra che visualizza il proprio hardisk e permette
selezionare il file. Questo widget inoltre ha il compito di prelevare il
nome del file. Il form invece è necessario in quanto è da questa struttura
che viene inviato il file. Questo widget permette di avviare un servlet
senza necessità di una RPC. Infatti il servlet sarà un’estensione
dell’HttpServlet e conterrà al suo interno l’implementazione del metodo
doPost() utilizzato per memorizzare effettivamente i dati nel server. La
soluzione utilizzata è molto simile a quella per costruire i dati necessari
alla creazione dell’albero asincrono (in quel caso si creava una stringa
XML).
99
CAPITOLO 6 - CONCLUSIONI
In questo capito conclusivo della tesi verranno presentate le mie
conclusioni personali riguardante il progetto, inteso nel suo complesso,
non solamente riguardo la cartella clinica. Verranno analizzati gli
obiettivi raggiunti ed eventualmente quelli a cui non è stato possibile
arrivare. Sarà fatta un’autocritica riguardo ai problemi che purtroppo
possono sorgere nell’utilizzo del software creato ed inoltre saranno
presentati alcuni possibili miglioramenti. In ultimo verrà anche proposta
un’analisi comparativa tra il vecchio portale Miro realizzato con
tecnologia Ruby On Rails e quello attualmente realizzato.
6.1 Obiettivi raggiunti
Gli obiettivi che erano stati prefissati quando ci è stato affidato lo
sviluppo di questa applicazione sono stati a pieno raggiunti: creare un
portale pienamente funzionale atto a svolgere compiti di telemedicina,
quindi di interfacciare le figure del requester e del dottore.
L’apprendimento della nuova tecnologia GWT è stato sicuramente
raggiunto, anche grazie alle svariate documentazioni presenti sul web.
C’è anche da dire che a rendere difficile e poco immediato l’utilizzo di
questo framework ci si è messa la sua non moltissima diffusione.
Cercare un portale completamente costruito tramite il GWT, come del
resto lo è questo, non è cosa semplice: spesso le soluzioni trovate
includevano altre tecnologie ausiliarie.
Un altro fattore che ha reso difficile raggiungere una certa
dimestichezza con il GWT, soprattutto per chi come me magari
proveniva dall’utilizzo di tecnologie più “classiche” come possono
100
Capitolo
6
–
Conclusioni
essere il PHP o l’ASP, è stato senza dubbio l’obbligatorio utilizzo delle
RPC.
Per quanto riguarda invece la stesura e la finalizzazione del portale,
posso essere senz’altro soddisfatto del prodotto ottenuto in quanto
realizza a pieno le specifiche richieste, sia dal punto di vista
tecnologico-universitario, sia dal punto di vista della telemedicina.
L’obiettivo universitario è stato precedentemente affrontato, mentre per
quanto riguarda quello medico, si può senz’altro dire che il portale
rispecchia tutte quelle caratteristiche e quei valori imposti dalla
telemedicina: la semplicità e la possibilità di utilizzo da parte di
chiunque è stata alla base della creazione di tutte le pagine realizzate.
6.2 Problemi riscontrati
Qui vengono ora presentati i problemi incontrati durante la
realizzazione del portale. Alcuni sono stati già presentati nelle singole
pagine della cartella clinica, quindi qui si cercherà di dare una visione
generale di tutti i problemi affrontati dal nostro gruppo di lavoro.
I problemi iniziali sono avvenuti soprattutto nel realizzare la
comunicazione lato client e server, nonché il prelevamento o la
manipolazione dei dati nel database. Infatti, come sopra detto, le RPC
inizialmente realizzate non sempre esaudivano le nostre richieste:
questo è accaduto soprattutto per l’utilizzo del meccanismo di passaggio
del controllo server-client tramite il metodo onSuccess() dell’oggetto
AsyncCallback.
Altre difficoltà si sono senz’altro incontrate nell’effettuare l’upload
di un file nel server. Questo non deriva da problemi legati al GWT, ma
101
Capitolo
6
–
Conclusioni
alla gestione dei permessi necessari in determinate cartelle e concessi
solamente a determinati utenti: ci siamo quindi creati un utente con i
giusti permessi necessari alla risoluzione del problema.
6.3 Miglioramenti Possibili
Nella creazione di questo portale, purtroppo, essendo alle prime
armi nel costruire un portale per la telemedicina e nell’utilizzo del
workspace GWT, devo riconoscere che magari alcune parti del portale
possono essere migliorate. Naturalmente anche il fatto di lavorare in
team ha provato alcuni svantaggi in questo senso, a causa magari di
incomprensioni e via dicendo.
In questa sezione verranno affrontati i possibili miglioramenti che si
potrebbero sviluppare in futuro.
Partiamo inizialmente da com’è gestita la parte che permette al
dottore ed al requester di interagire con i problemi clinici del paziente.
Questa parte a mio parere è stata creata non pensando molto alla sua
usabilità. Per molti di noi che utilizzano spesso il computer può
rimanere semplice, ma per coloro a cui è destinato tale software e i quali
non sempre hanno esperienze in tal senso, magari questa sezione
potrebbe risultare abbastanza complicata da utilizzare. Magari era
meglio affrontare lo stesso problema come con le altre parti della
cartella clinica, ovvero tramite una toolbar con le varie opzioni presenti.
Questo sarebbe senz’altro più simile ad altri software, magari conosciuti
dall’utilizzatore, ed avrebbe risparmiato il tempo di apprendimento.
Un’altra situazione che poteva magari essere meglio gestita è quella
relativa alla gestione dei messaggi. Infatti non è stata prevista la risposta
102
Capitolo
6
–
Conclusioni
da parte del requester. Questo secondo la mia opinione dovrebbe essere
possibile, in quanto magari allo stesso requester viene chiesto di fornire
informazioni di natura diversa di quelle inseribili: la comunicazione tra
le due parti dovrebbe sempre essere la più ampia e semplice possibile.
Sempre relativo alla gestione dei messaggi, ma anche per quanto
riguarda i referti, nel nostro portale manca la possibilità di cancellare
quest’ultimi. Dovrebbe essere creato un cestino che favorisca questo
meccanismo, in cui magari vengono posizionati, a discrezione
dell’utente, i report non più interessanti. Successivamente si potrebbe
impostare una rimozione automatica basata sulla permanenza nel
cestino, come del resto accade per molte caselle di posta elettronica.
Tutto questo eviterebbe il possibile sovraccarico, con conseguente
lentezza, del server.
Un altro aspetto importante che non è stato implementato nel
portale è stato quello gestire temporalmente tutte le modifiche. Questo
significava creare un portale che mappasse temporalmente tutte le
modifiche effettuate dal requester. Per ogni modifica verrebbe quindi
memorizzata ora e giorno in cui viene effettuata, così da sapere magari
se un report è effettuato prima o dopo che la modifica è stata fatta.
Anche questo meccanismo fornirebbe una maggior chiarezza e
trasparenza nelle informazioni trasmesse.
Un altro difetto, ma questo non è stato purtroppo non è dipeso da
noi, resta il fatto della compatibilità tra i vari browser. Infatti, anche se
questa è data al 100% con tutti i browser, non è del tutto esatto. Il
diverso comportamento dei vari browser ci ha costretto alla creazione di
diverse procedure in più: per esempio nell’aggiornare l’albero asincrono
è stato dovuto creare un metodo apposito per renderlo compatibile con
Internet Explorer, altrimenti l’aggiornamento non risultava dinamico.
103
Capitolo
6
–
Conclusioni
Queste piccole accortezze hanno rallentato di molto il nostro lavoro in
fase finale in quanto, per ottenere un buon prodotto, questo deve senza
dubbio funzionare su qualunque browser.
Un possibile miglioramento, che però stravolgerebbe di non poco la
struttura del portale, sarebbe quello di dare la possibilità anche di
effettuare telemedicina in real-time, ovvero tramite video conferenze e
simili. Questo senz’altro amplierebbe gli orizzonti di utilizzo del nostro
portale. Il lavoro per apportare tale modifica risulterebbe senz’altro
molto notevole, ma aumenterebbe di gran lunga la possibilità di offrire
una telemedicina completa ed adatta ad ogni situazione. Tale
miglioramento ovviamente includerebbe anche l’utilizzo di altre
tecnologie informatiche e aumenterebbe purtroppo i costi.
6.4 Confronti con altre tecnologie
In questa sezione verrà effettuato il confronto tra la tecnologia
utilizzata nello sviluppo, ovvero il GWT, ed altre tecnologie da me
conosciute come il PHP e il JSP.
Partiamo con l’analisi di confronto con il PHP. Il PHP è un
linguaggio di scripting interpretato che riprende per molti versi le
sintassi del C e del Perl e dalla versione 5 migliora il supporto al
paradigma ad oggetti. Dopo questa breve introduzione verranno fatte
notare le differenze.
Il GWT per la visualizzazione utilizza dei widget che permettono di
rendere all’utente di creare interfacce graficamente complesse, in modo
semplice e rapido. Il PHP per la visualizzazione lato client non ha
particolari accorgimenti, in quanto utilizza i tag HTML così come sono.
104
Capitolo
6
–
Conclusioni
Per quanto riguarda la gestione del lato server invece a mio avviso
il PHP è più semplice ed intuitivo in quanto non necessita di chiamate
remote particolari e viene tutto eseguito in quella pagina: l’integrazione
con il database, MySQL in particolare, è immediata e più rapida di
quanto non lo sia in GWT. Infatti in GWT per reperire un dato dal
database, il meccanismo che vi sta dietro è senza dubbio più complicato
perché si basa su delle RPC. Soprattutto la gestione dei dati di ritorno e
l’utilizzo di essi nel solo metodo onSuccess() del client, rende questa
tecnologia forse un po’ troppo macchinosa. Infatti è proprio questa
concezione di netta separazione tra client e server presente nel GWT che
lo rende molto differente dal PHP.
Un altro punto che gioca a favore del PHP è quello della velocità.
Infatti, a meno che non si stia usando un browser di ultima generazione
ed una connessione ad internet veloce, con il GWT, a causa della
presenza di complesse interfacce lato client, il caricamento iniziale della
pagina è molto più lento di una pagina in PHP. A favore del GWT c’è
però da dire che caricata la pagina, il successivo scambio delle “viste” è
molto più rapido, perché in realtà si svolge all’interno della stessa
pagina tramite procedure AJAX e JavaScript.
Ricapitolando le due tecnologie hanno alcuni punti a loro vantaggio
ed altri a loro svantaggio. Si può quasi dire che si completano. In molte
guide trovate sul web, una cosa che ho felicemente notato, è che il GWT
può tranquillamente essere compatibile con l’utilizzo di altre tecnologie.
Infatti l’utilizzo del PHP assieme al GWT è molto utilizzato perché
appunto tende a sfruttare solamente i vantaggi delle due: il GWT viene
utilizzato per impostare la parte grafica così da avere un’interfaccia
senza dubbio molto più innovativa; il PHP viene utilizzato nelle
procedure lato server per interfacciarsi al database.
105
Capitolo
6
–
Conclusioni
C’è da dire che comunque i risultati che si ottengono dall’utilizzo
della tecnologia di Google sono molto importanti e vertono verso una
nuova concezione di sito web, sempre più simile ad un’applicazione.
Sicuramente essa potrà essere una tecnologia innovativa per il futuro e
grazie al suo continuo miglioramento potrà senza dubbio anche ampliare
la sua diffusione nel presente.
Per quanto riguarda il confronto con il JSP posso dire che le due
tecnologie non differiscono di molto nei meccanismo che utilizzano.
Lato client c’è la stessa differenza che è stata evidenziata con il PHP,
ovvero l’enorme potenzialità in più offerta da GWT tramite i suoi
widget.
Per quanto riguarda il lato server invece le due tecnologie si
assomigliano. È vero che non vengono effettuate RPC nella stessa
maniera che del GWT, ma i servlet utilizzati nel JSP in realtà sono gli
stessi. Solamente la concezione di serializzazione dei dati non è così
rigida, ma per il resto le procedure interne del servlet sono esattamente
le stesse.
Si può quindi affermare che non esiste, a differenza del PHP un
reale vantaggio del JSP rispetta al GWT. Da far notare infatti come
questa tecnologia sia un po’ in disuso e man mano sia superata da altre
tecnologie, quali il GWT.
In conclusione possiamo dire che il vero punto di forza del GWT
sono la creazione di interfacce molto belle graficamente quanto
funzionali. Come punto a suo sfavore giocano invece i suoi “complessi”
meccanismi, rispetto ad altre tecnologie, di gestire il lato server. Questi
meccanismo però, possono anche essere semplificati dall’utilizzo di
106
Capitolo
6
–
Conclusioni
altre tecnologie ausiliarie. Il risultato è che il GWT, generando codice
JavaScript, si rende compatibile anche ad essere interfacciato con altri
linguaggi.
6.5 Confronto con “Miro On Rails”
Innanzitutto bisogna spiegare che cosa sia il Miro On Rails. Il Miro
è il vecchio portale precedente a questo, creato per offrire il medesimo
servizio, ma basato su tecnologia Ruby On Rails: da qui il nome Miro
On Rails. Il risultato ottenuto è profondamente differente. Non cercherò
di giudicare la differenza tra le due tecnologie utilizzate in quanto non
ho le basi necessarie del Ruby On Rails per argomentarle, ma verrà
affrontato il discorso basandosi puramente sul risultato finale.
Analizzando il prodotto finale quello che salta subito all’occhio è la
notevole differenza nelle interfacce grafiche. Come per gli altri
linguaggi prima confrontati, anche qui il GWT non ha paragoni e offre
senza dubbio un servizio migliore. Anche qui la cartella clinica viene
gestita tramite dei tab, ma certamente l’utilizzo non è così immediato
come quello del nostro portale. Infatti la grafica qui presente è molto
minimale. C’è da dire a favore di questo portale che, essendo così
scarno graficamente, sono presenti solamente le cose essenziali ed il sito
perciò non risulta appesantito.
Al di la delle singole soluzioni utilizzate, nel totale il portale è stato
concepito in modo del tutto differente. Infatti nel nostro progetto
abbiamo scelto di rendere sempre visibili più informazioni possibili,
utilizzando il concetto di Window presente in GWT: tutti i dati vengono
aperti in un pop-up e anche se sembra banale, le informazioni sottostanti
107
Capitolo
6
–
Conclusioni
possono sempre essere controllate. Nel portale Miro invece questo è
ovviamente impossibile, in quanto ogni pagina è isolata e necessita di
un caricamento a parte.
Per quanto riguarda la cartella clinica invece la differenza è ancora
più profonda. Entrando nella cartella clinica da noi sviluppata, l’utente
loggato si trova subito davanti una struttura semplice ed immediata
offerta dall’albero laterale, che lo tiene sempre aggiornato riguardo le
patologie presenti. Nel Miro questo colpo d’occhio iniziale viene meno
in quanto in realtà non c’è una netta divisione tra cartella clinica e resto
dei dati. Un confronto a livello grafico può essere effettuato da queste
due immagini (fig. 6.1 e fig 6.2).
Figura 6.1
108
Capitolo
6
–
Conclusioni
Figura 6.2
La tecnologia del Miro risulta senza dubbio più accessibile a chi
possiede una connessione di banda limitata o lenta. Nel caso del GWT il
lato client è molto appesantito da tutti i widget presenti e solamente
grazie alla tecnologia AJAX questo è meno sentito. Con il Ruby On
Rails invece questo non accade e l’utente difficilmente ha problemi di
banda.
Quindi a parte la grafica in realtà nei meccanismi i due portali si
equivalgono. Infatti hanno lo stesso database, con applicate alcune
modifiche in più dovute alle maggiori opzioni che sono state sviluppate
nel nuovo progetto. Sono state apportate modifiche riguardo ai dati dei
pazienti e degli utenti: non era, ad esempio, realizzata la possibilità di
modifica dei dati del paziente nonché dell’utente. Ci si discosta molto
quindi dal rendere questo portale simile ad un’applicazione normale.
Un'altra netta differenza è anche quella riguardante la gestione dei
permessi: nel Miro è suddivisa su di tre livelli, ovvero amministratore,
requester e dottore; nel MedTel invece è suddivisa in quattro livelli
gerarchici, ovvero con in più la figura intermediaria del manager e la
109
Capitolo
6
–
Conclusioni
scelta del super amministratore univoco. Questa scelta amministrativa a
mio avviso rende la gestione di gran lunga più efficace ed efficiente,
soprattutto in previsione di una possibile diffusione.
6.6 Considerazioni finali sul tirocinio
Nel trarre conclusioni sul tirocinio svolto posso ritenermi senz’altro
molto soddisfatto della scelta effettuata. Sebbene il lavoro svolto è stato
molto impegnativo ritengo che il prodotto creato sia di buon livello. A
livello personale inoltre ho rafforzato le mie attitudini al lavoro in team,
cosa che ritengo molto importante soprattutto nell’ottica di un futuro
lavoro da ingegnere informatico. Inoltre ho potuto imparare a conoscere
ed usare una nuova tecnologia come il GWT, approfondendo tra l’altro
il Java da me già conosciuto.
Mi sono quindi reso conto dell’importanza di internet come fonte
infinita di informazioni. Ho imparato anche a reperire meglio le
informazioni nel web, in quanto senza di esse non si poteva procedere:
la ricerca ininterrotta di informazioni su internet, specialmente se non
presenti nella propria lingua, può essere abbastanza problematica e
allungare i tempi di lavoro. Trovare i giusti risultati tra le molteplici
pagine web ha espanso la mia conoscenza.
Tutta questa esperienza ha ampliato senza dubbio le mie esperienze
nell’ambito del web designer e nella gestione di software per internet.
La possibilità di confrontarsi su temi attuali e soddisfare problemi reali
ha reso sicuramente questo tirocinio molto interessante: il confronto con
gli ingegneri della ASUR, soprattutto con l’ing. Giampieri, mi ha senza
dubbio fornito un giusto metodo di lavoro. Posso quindi concludere
110
Capitolo
6
–
Conclusioni
dicendo di avere perfezionato, grazie a questa mia esperienza, la mia
metodologia nell’affrontare i problemi che mi si pongono di fronte.
In particolar modo vorrei citare i tirocinanti Ausili Andrea, Pongetti
Francesco, Prencipe Giuseppe e Torelli Luca che hanno collaborato con
me alla realizzazione di questo software e con cui ho affrontato e risolto
i problemi incontrati. Un ringraziamento va anche al prof. Dragoni che è
sempre stato disponibile per ogni nostro dubbio e per ogni nostro
chiarimento.
In conclusione quindi ringrazio tutte le persone che mi hanno
fornito un supporto e hanno contribuito alla mia formazione durante
questo tirocinio.
111
APPENDICE – CODICE SORGENTE
Vengono qui presentate quattro classi, due relative alla clinical
folder e due relative alla sezione dell’allergia. Sono state scelte queste
classi perché le prime racchiudono tutti i meccanismi della clinical
folder, mentre le seconde sono da esempio per tutte le sezioni interne
dell’anamnesi della stessa cartella clinica. Le classi sono complete e
contengono tutto il codice Java: si è scelto di inserire tutte le righe del
codice sorgente, non solo delle porzioni, in quanto si è voluto dare una
visione completa dei meccanismi del GWT. Ovviamente ognuna delle
due classi è fornita del codice lato client e lato server.
Ecco qui presente il codice sorgente:
Clinical Folder – Lato client
public class ClinicalFolder extends Composite {
/*
*
* VARIABILI PUBLIC UTILIZZATE ANCHE NEI METODI ESTERNI
*
*/
public String type=new String();
public String idGenitore=new String();
public String idFiglio=new String();
public AsyncTreeNode anamnesis, anamnesis2;
public TabPanel tabPanel = new TabPanel();
public Menu rightClickMenu;
final TreePanel treePanel;
final Window window;
final TreeNode root;
public TreeNode profile,problems;
final TabPanel tabArea;
public String id_event, patient, id_patient;
/*
* COSTRUTTORE GRAFICO
*/
112
Appendice
–
Codice
Sorgente
public ClinicalFolder(Window window, final TabPanel tabArea) {
this.tabArea = tabArea;
this.window=window;
final AbsolutePanel absolutePanel = new AbsolutePanel();
initWidget(absolutePanel);
//propriety tabPanel
tabPanel.setResizeTabs(true);
tabPanel.setMinTabWidth(100);
tabPanel.setTabWidth(130);
tabPanel.setEnableTabScroll(true);
tabPanel.setWidth(450);
tabPanel.setHeight(250);
tabPanel.addListener(new TabPanelListenerAdapter() {
public void onContextMenu(TabPanel
source, Panel tab, EventObject e) {
source.activate(tab.getId());
showRightMenu(tab, e);
}
});
//tree panel
treePanel = new TreePanel();
treePanel.setWidth(230);
treePanel.setAnimate(true);
treePanel.setEnableDD(false);
treePanel.setContainerScroll(true);
treePanel.setRootVisible(true);
treePanel.setCollapsible(true);
treePanel.setAutoScroll(true);
treePanel.setSelectionModel(new MultiSelectionModel());
treePanel.setTitle("");
treePanel.expandAll();
root = new TreeNode("Clinical Folder");
root.setSingleClickExpand(true);
root.setIcon("books.gif");
treePanel.setRootNode(root); //padre di tutti
//figli ----------------------------/*
* PATIENT PROFILE
*
*/
profile = new TreeNode("Patient Profile");
profile.setTooltip("Patient Profile");
profile.setIcon("medicon1.png");
profile.setId("patientProfile");
profile.addListener(new TreeNodeListenerAdapter(){
public void onClick( Node node, EventObject e) {
if (!tabPanel.hasItem("patientProfile")){
//tab del ramo Patient Profile
final Panel tabPatientProfile = new Panel();
113
Appendice
–
Codice
Sorgente
tabPatientProfile.setTitle("Patient Profile");
tabPatientProfile.setId("patientProfile");
tabPatientProfile.setBaseCls("gwt-profile");
tabPatientProfile.setAutoScroll(true);
tabPatientProfile.setClosable(true);
Toolbar toolbar=createPatientToolbar();
if (type.equalsIgnoreCase("requester"))
tabPatientProfile.setTopToolbar(toolbar);
tabPatientProfile.add(new PatientProfile());
tabPanel.add(tabPatientProfile); //aggiunge il
pannello "tab1" al TabPanel "tabPanel"
tabPanel.activate("patientProfile");
}
else{
tabPanel.activate("patientProfile");
}
}
});
root.appendChild(profile);
//tab del ramo Patient Profile
final Panel tabPatientProfile = new Panel();
tabPatientProfile.setTitle("Patient Profile");
tabPatientProfile.setId("patientProfile");
tabPatientProfile.setBaseCls("gwt-profile");
tabPatientProfile.setAutoScroll(true);
tabPatientProfile.setClosable(true);
Toolbar toolbar=createPatientToolbar();
tabPatientProfile.setTopToolbar(toolbar);
tabPatientProfile.add(new PatientProfile());
tabPanel.add(tabPatientProfile); //aggiunge il pannello
"tab1" al TabPanel "tabPanel"
tabPanel.activate("patientProfile");
/*
* ANAMNESIS
*
* albero dinamico
*
*/
final XMLTreeLoader loader = new XMLTreeLoader();
loader.setDataUrl("XmlAnamnesis");
loader.setMethod(Connection.POST);
loader.setRootTag("anamnesis");
loader.setQtipMapping("@qtip");
loader.setIconMapping("@icon");
loader.setFolderIdMapping("@id");
loader.setFolderTitleMapping("@title");
loader.setFolderTag("element");
loader.setLeafIdMapping("@id");
loader.setLeafTitleMapping("@title");
loader.setLeafTag("subelement");
anamnesis = new AsyncTreeNode("Anamnesis", loader);
114
Appendice
–
Codice
Sorgente
root.appendChild(anamnesis);
anamnesis.setSingleClickExpand(true);
anamnesis.setIcon("anamnesis.gif");
/*
* refresh dell'albero
*/
treePanel.addTool(new Tool(Tool.REFRESH, new Function()
{
public void execute() {
// MultiSelectionModel selectionModel =
(MultiSelectionModel) treePanel.getSelectionModel();
//TreeNode[] nodes =
selectionModel.getSelectedNodes();
treePanel.getEl().mask("Loading", "x-maskloading");
treePanel.expandAll();
anamnesis.reload();
reloadTree();
anamnesis.collapse(true, false);
//TreeNode nodeSelected=nodes[0];
Timer timer = new Timer() {
public void run() {
treePanel.getEl().unmask();
anamnesis.expand(true, true);
}
};
timer.schedule(1000);
// nodeSelected.select();
}
}, "Refresh"));
/*
*
* PATIENT CLINICAL PROBLEMS
*
*
*/
problems = new TreeNode("Patient Clinical Problems");
problems.setIcon("medicon2.png");
problems.setId("clinicalProblem");
problems.addListener(new TreeNodeListenerAdapter() {
public void onClick(Node node, EventObject event) {
if (!tabPanel.hasItem("clinicalProblem")){
//tab del ramo Patient Profile
final Panel tabClinicalProblem = new Panel();
tabClinicalProblem.setTitle("Patient Clinical
Problems");
tabClinicalProblem.setId("clinicalProblem");
tabClinicalProblem.setBaseCls("gwt-problems");
tabClinicalProblem.setAutoScroll(true);
tabClinicalProblem.setClosable(true);
//controlla il tipo di utente loggato
if (type.equalsIgnoreCase("requester"))
tabClinicalProblem.add(new
PatientClinicalProblem());
115
Appendice
–
Codice
Sorgente
else
tabClinicalProblem.add(new
ViewVisitsEvent(id_event,patient,id_patient));
tabPanel.add(tabClinicalProblem); //aggiunge il
pannello "tab1" al TabPanel "tabPanel"
tabPanel.activate("clinicalProblem");
}
else{
tabPanel.activate("clinicalProblem");
}
}
});
root.appendChild(problems);
/*
* layout per la visualizzazione
*
*/
BorderLayoutData centerData = new
BorderLayoutData(RegionPosition.CENTER);
centerData.setMargins(3, 0, 3, 3);
BorderLayoutData westData = new
BorderLayoutData(RegionPosition.WEST);
westData.setSplit(true);
westData.setMargins(3, 3, 3, 3);
westData.setCMargins(0, 2, 0, 0);
/*
*
* Costruzione della finestra
*
*/
//tutta la finestra
// window = new Window();
window.setTitle(" Patient Clinical Folder");
window.setClosable(true);
window.setWidth(1049);
window.setHeight(530);
window.setPlain(true);
window.setLayout(new BorderLayout());
window.add(tabPanel, centerData); //aggiunge tabPanel che
il contenitore di visualizzazione
window.add(treePanel, westData);
window.setCloseAction(Window.CLOSE);
window.setMaximizable(true);
window.setIconCls("image");
window.setModal(true);
/*
* Tool per visualizzare una window per l'help
*/
window.addTool(new Tool(Tool.HELP, new Function() {
public void execute() {
Panel windowPanel=new Panel();
windowPanel.setHtml(getHelp());
Window windowHelp = new Window();
windowHelp.setTitle("Help");
116
Appendice
–
Codice
Sorgente
windowHelp.setMaximizable(false);
windowPanel.setPaddings(5);
windowHelp.setResizable(false);
windowHelp.setWidth(500);
windowHelp.setModal(true);
windowHelp.add(windowPanel);
windowHelp.show();
}
}, "HELP"));
window.show();
window.maximize();
/*
* Listener che viene richiamato ad ogni click
* su qualsiasi nodo dell'albero
*
*/
treePanel.addListener(new TreePanelListenerAdapter(){
public void onClick(final TreeNode node, EventObject e) {
//
System.out.println(node.getText()+" with
idFiglio= "+node.getId()+" and idGenitore=
"+node.getParentNode().getId());
/*
* id del padre ------ da utilizzare in presenza di
figli per aprire pagine
*/
idGenitore=node.getParentNode().getId();
/*
* id del figlio ------ da utilizzare quando nn ci
sono figli
*/
idFiglio=node.getId();
System.out.println("idFiglio nuovo="+idFiglio);
/*
* PADRI -- VERIFICA ID TRAMITE "idFiglio"
*
perche senza genitori con id valido
*
*/
if (idFiglio.equals("familiars")){
addTab(node);
//tab.add(new Familiars());
}
if (idFiglio.equals("allergologies")){
addTab(node);
// tab.add(new Allergology());
}
if (idFiglio.equals("family_pathologies")){
addTab(node);
//tab.add(new Allergology());
117
Appendice
–
Codice
Sorgente
}
if (idFiglio.equals("pathologicals")){
addTab(node);
// tab.add(new Pathologicals());
}
if (idFiglio.equals("physiologicals")){
addTab(node);
//tab.add(new Phisiological());
}
/*
*
* FIGLI --*
padre con le info generiche
*
*
*/
VERIFICA ID TRAMITE "idGenitore"
perche tramite apro la pagina del
poi rese specifiche dalla query SQL
//VERIFICA ID FIGLI e SETTA L'ID SULLA
SESSIONE
if (idGenitore.equals("allergologies")){
setIdSelected(node);
//addTabChild(node);
}
if (idGenitore.equals("family_pathologies")){
setIdSelected(node);
// addTabChild(node);
//selected.setId(idFiglio.substring(1),
callback);
}
if (idGenitore.equals("pathologicals")){
setIdSelected(node);
// addTabChild(node);
}
}
});
/*
* RPC CHE AVVIENE AL CARICAMENTO
* VISUALIZZA IL NOME
*
*/
ClinicalFolderRSAsync view = (ClinicalFolderRSAsync)
GWT.create(ClinicalFolderRS.class); //crea il servizo
ServiceDefTarget endpoint = (ServiceDefTarget) view;
endpoint.setServiceEntryPoint(GWT.getModuleBaseURL() +
"ClinicalFolderRS");
AsyncCallback callback = new AsyncCallback() {
public void onSuccess(Object result) {
ArrayList values=(ArrayList) result;
treePanel.setTitle("Patient:
"+values.get(0).toString().toUpperCase());
type=values.get(1).toString();
if (!type.equalsIgnoreCase("requester"))
118
Appendice
–
Codice
Sorgente
tabPatientProfile.getTopToolbar().destroy();
}
public void onFailure(Throwable caught) {
System.out.println("errore nella view");
}
};
view.view(callback);
/*
* AGGIORNA LA GRIGLIA
*/
this.window.addListener(new WindowListenerAdapter() {
public void onClose(Panel panel) {
String idActive=tabArea.getActiveTab().getId();
tabArea.remove("lastclinical");
ViewEventsRequest env;
EventsPatients env1;
Panel pan = new Panel();
Panel lastP;
pan.setBorder(false);
pan.setPaddings(0);
pan.setLayout(new HorizontalLayout(0));
if (type.equalsIgnoreCase("requester")){
env = new ViewEventsRequest(tabArea);
pan.add(env);
lastP = new Panel();
lastP.setTitle("Last Clinical Problem");
}
else{
env1=new EventsPatients(tabArea);
pan.add(env1);
lastP = new Panel();
lastP.setTitle("Clinical Problems");
}
lastP.setPaddings(0);
lastP.setId("lastclinical");
lastP.setSize(709, 600);
lastP.setAutoScroll(true);
lastP.add(pan);
tabArea.add(lastP);
tabArea.setActiveTab(idActive);
}
});
}
/*
*
* METODI ESTERNI ----------------------------------*
119
Appendice
–
Codice
Sorgente
*
*/
/*
* METODO
*
*
*
*/
PER L'AGGIUNTA DI UN TAB
"PADRE"
public Panel addTab(final TreeNode node){
if (!tabPanel.hasItem(idFiglio)){ //CONTROLLA SE GIA ESISTE
QUEL TAB
Panel tab=new Panel();
tab.setBaseCls("gwt-el");
tab.addListener(new PanelListenerAdapter(){
public void onActivate(Panel tab) { //quando attivo
il pannello
AnamnesisView.setLabel();
node.select();
MultiSelectionModel selectionModel =
(MultiSelectionModel) treePanel.getSelectionModel();
TreeNode[] nodes =
selectionModel.getSelectedNodes();
idFiglio=nodes[0].getId();
System.out.println("idFiglio
nell'addTab="+idFiglio);
}
});
Toolbar toolbar=createToolbar();
if (type.equalsIgnoreCase("requester"))
tab.setTopToolbar(toolbar);
//aggiunge un pulsante per il refresh
if (idFiglio.equals("allergologies")||
idFiglio.equals("family_pathologies")||
idFiglio.equals("pathologicals")){
Button buttonRefresh=new Button("Refresh");
buttonRefresh.setIcon("refresh.gif");
buttonRefresh.addListener(new ButtonListenerAdapter() {
public void onClick(final Button button, final
EventObject e) {
refreshPage();
}
});
tab.addButton(buttonRefresh);
}
tab.setTitle(node.getText());
tab.setClosable(true);
tab.setId(idFiglio);
tab.setAutoScroll(true);
tabPanel.add(tab);
selectCompositeView(idFiglio,tab);
120
Appendice
–
Codice
Sorgente
return tab;
}
else {
tabPanel.setActiveItemID(idFiglio);
return null;
}
}
/*
* METODO PER L'AGGIUNTA DI UN TAB
*
*
"FIGLIO"
*
*/
public Panel addTabChild(final TreeNode node){
if (!tabPanel.hasItem(idGenitore.substring(0,
6)+""+idFiglio)){
Panel tab=new Panel();
tab.setBaseCls("gwt-sub");
tab.addListener(new PanelListenerAdapter(){
public void onActivate(Panel panel) {
//quando attivo il pannello
node.select();
MultiSelectionModel selectionModel =
(MultiSelectionModel) treePanel.getSelectionModel();
TreeNode[] nodes =
selectionModel.getSelectedNodes();
idFiglio=nodes[0].getId();
setIdSelected();
System.out.println("idFiglio
nell'addTabChild="+idFiglio);
}
});
Toolbar toolbar=createToolbar();
if (type.equalsIgnoreCase("requester"))
tab.setTopToolbar(toolbar);
tab.setTitle(node.getText());
tab.setClosable(true);
tab.setId(idGenitore.substring(0, 6)+""+idFiglio);
selectCompositeChild(idGenitore,tab);
tab.setAutoScroll(true);
tabPanel.add(tab);
tabPanel.activate(idGenitore.substring(0,
6)+""+idFiglio);
return tab;
} else {
tabPanel.setActiveItemID(idGenitore.substring(0,
6)+""+idFiglio);
return null;
}
}
/*
121
Appendice
–
Codice
Sorgente
* METODO PER LA SCELTA DELLA PAGINA DA VISUALIZZARE
*
*
"PADRE"
*
*/
public void selectCompositeView(final String name,final Panel
panel){
if(name.equals("familiars") ||
name.equals("physiologicals")){
AnamnesisViewRSAsync tab = (AnamnesisViewRSAsync)
GWT.create(AnamnesisViewRS.class); //crea il servizo
ServiceDefTarget endpoint = (ServiceDefTarget) tab;
endpoint.setServiceEntryPoint(GWT.getModuleBaseURL() +
"AnamnesisViewRS");
AsyncCallback callback = new AsyncCallback() {
public void onSuccess(Object result) {
ArrayList rows=(ArrayList) result;
if
(!rows.get(0).toString().equals("0")){
if (name.equals("familiars"))
panel.add(new
FamiliarsView(ClinicalFolder.this));
if
(name.equals("physiologicals"))
panel.add(new
PhisiologicalView());
}
else
panel.add(new
AnamnesisView(ClinicalFolder.this));
tabPanel.activate(idFiglio);
}
public void onFailure(Throwable caught) {
MessageBox.alert("ERROR");
}
};
tab.view(name, callback);
}
/*if (name.equals("familiars")){
panel.add(new FamiliarsView(ClinicalFolder.this));
}*/
if (name.equals("allergologies")){
panel.add(new AnamnesisView(ClinicalFolder.this));
tabPanel.activate(idFiglio);
}
if (name.equals("pathologicals")){
panel.add(new AnamnesisView(ClinicalFolder.this));
tabPanel.activate(idFiglio);
}
/* if (name.equals("physiologicals")){
panel.add(new PhisiologicalView());
}*/
if (name.equals("family_pathologies")){
panel.add(new AnamnesisView(ClinicalFolder.this));
122
Appendice
–
Codice
Sorgente
tabPanel.activate(idFiglio);
}
}
/*
* METODO
*
*
*
*/
PER LA SCELTA DELLA PAGINA DA VISUALIZZARE
"FIGLI"
private void selectCompositeChild(String id,Panel panel){
if (id.equals("allergologies")){
panel.add(new AllergologyView(ClinicalFolder.this));
}
if (id.equals("family_pathologies")){
panel.add(new Family());
}
if (id.equals("pathologicals")){
panel.add(new PathologicalsView());
}
}
/*
* METODO PER L'AGGIORNAMENTO DELLE PAGINE "MODIFICATE"
*
*
*/
public void updateTab(Panel tab,Panel newTab){
String id=tab.getId(); //non l'id del db
newTab.setId(id);
System.out.println("id nell'update="+idFiglio);
//idFiglio=id.substring(6,id.length());
tabPanel.remove(tab.getId());
tabPanel.add(newTab);
tabPanel.activate(newTab.getId());
tabPanel.setActiveItemID(newTab.getId());
tabPanel.setActiveTab(newTab.getId());
}
/*
*
* METODO PER LA RICARICA DELL'ALBERO ASYNC
*
*/
public void reloadTree(){
//anamnesis.reload();
anamnesis.remove();
anamnesis.destroy();
//root.removeChild(anamnesis);
final XMLTreeLoader loader2 = new XMLTreeLoader();
loader2.setDataUrl("XmlAnamnesis");
loader2.setMethod(Connection.POST);
loader2.setRootTag("anamnesis");
loader2.setQtipMapping("@qtip");
loader2.setIconMapping("@icon");
loader2.setFolderIdMapping("@id");
loader2.setFolderTitleMapping("@title");
123
Appendice
–
Codice
Sorgente
loader2.setFolderTag("element");
loader2.setLeafIdMapping("@id");
loader2.setLeafTitleMapping("@title");
loader2.setLeafTag("subelement");
anamnesis = new AsyncTreeNode("Anamnesis", loader2);
anamnesis.setSingleClickExpand(true);
anamnesis.setIcon("anamnesis.gif");
root.insertBefore(anamnesis, problems);
treePanel.expandAll();
}
/*
*
* METODO PER L'AGGIUNTA DELLA TOOLBAR
*
*/
public Toolbar createToolbar(){
Toolbar toolbar = new Toolbar();
final Menu menu = new Menu();
menu.setShadow(true);
String id=idFiglio;
) {
if(id.equals("familiars") || id.equals("physiologicals")
//|| id.equals("physiologicals")){
/*
*
* Procedura con per vedere il numero di righe di
familiars e physiologicals
*
*/
AnamnesisViewRSAsync view = (AnamnesisViewRSAsync)
GWT.create(AnamnesisViewRS.class); //crea il servizo
ServiceDefTarget endpoint = (ServiceDefTarget)
view;
endpoint.setServiceEntryPoint(GWT.getModuleBaseURL() +
"AnamnesisViewRS");
AsyncCallback callback = new AsyncCallback() {
public void onSuccess(Object result) {
ArrayList rows=(ArrayList) result;
if
(!rows.get(0).toString().equals("0")){
addModifyMenu(menu);
menu.addSeparator();
addDeleteMenu(menu);
}
else {
addNewMenu(menu);
}
}
public void onFailure(Throwable caught) {
124
Appendice
–
Codice
Sorgente
MessageBox.alert("ERROR");
}
};
view.view(id, callback);
}
//aggiungo modifica, e delete x i menu figli
else if (id.substring(0, 1).equals("1") ||
id.substring(0, 1).equals("2") || id.substring(0, 1).equals("3")){
addModifyMenu(menu);
menu.addSeparator();
addDeleteMenu(menu);
}
else {
addNewMenu(menu);
menu.addSeparator();
addRefreshMenu(menu);
}
ToolbarButton toolbarButton=new ToolbarButton ("Option
Menu",menu);
ToolTip tip = new ToolTip();
tip.setTitle("Click here<br>to view more options");
tip.setDismissDelay(15000);
tip.setTrackMouse(true);
tip.applyTo(toolbarButton);
toolbarButton.setIcon("menu.gif");
toolbar.addFill();
toolbar.addSeparator();
toolbar.addButton(toolbarButton);
toolbar.addSeparator();
toolbar.addSpacer();
return toolbar;
}
public Toolbar createPatientToolbar(){
Toolbar toolbar = new Toolbar();
final Menu menu = new Menu();
menu.setShadow(true);
Item modify = new Item("Modify");
modify.setIcon("modify.gif");
modify.addListener(new BaseItemListenerAdapter(){
public void onClick(BaseItem item, EventObject e){
Window windowModify=new Window();
windowModify.setDraggable(true);
windowModify.setPlain(true);
windowModify.setModal(true);
windowModify.removeAll();
windowModify.setSize("820", "640");
windowModify.add(new
Patient(windowModify,ClinicalFolder.this,true,tabArea));
windowModify.show();
125
Appendice
–
Codice
Sorgente
}
});
menu.addItem(modify);
ToolbarButton toolbarButton=new ToolbarButton ("Option
Menu",menu);
ToolTip tip = new ToolTip();
tip.setTitle("Click here<br>to view more options");
tip.setDismissDelay(15000);
tip.setTrackMouse(true);
tip.applyTo(toolbarButton);
toolbarButton.setIcon("menu.gif");
toolbar.addFill();
toolbar.addSeparator();
toolbar.addButton(toolbarButton);
toolbar.addSeparator();
toolbar.addSpacer();
return toolbar;
}
/*
* L'ID UTILIZZATO QUI SARA:
* "idGenitore" ---->PER I FIGLI !!!
* "idFiglio" ---->PER I GENITORI !!!!
*
*/
private void selectModifyWindow(Window window){
System.out.println("id nell'modifyWindow="+idFiglio);
String id=idFiglio;
if (id.substring(0, 1).equals("1")){
window.setSize("700", "300");
window.add(new Allergology(window,ClinicalFolder.this,true));
}
if (id.equals("familiars")){
window.add(new Familiars(window,ClinicalFolder.this,true));
}
if (id.equals("physiologicals")){
window.add(new
Phisiological(window,ClinicalFolder.this,true));
}
if (id.substring(0, 1).equals("2")){
window.setSize("700", "300");
window.add(new
Pathologies(window,ClinicalFolder.this,true));
}
if (id.substring(0, 1).equals("3")){
window.setSize("700", "700");
window.add(new
Pathologicals(window,ClinicalFolder.this,true));
}
//aggiugere tutte le finestre da aprire
}
private void selectNewWindow(Window window){
126
Appendice
–
Codice
Sorgente
String id=idFiglio;
if (id.equals("allergologies")){
window.add(new
Allergology(window,ClinicalFolder.this,false));
}
if (id.equals("familiars")){
window.add(new
Familiars(window,ClinicalFolder.this,false));
}
if (id.equals("family_pathologies")){
window.add(new
Pathologies(window,ClinicalFolder.this,false));
}
if (id.equals("physiologicals")){
window.add(new
Phisiological(window,ClinicalFolder.this,false));
}
if (id.equals("pathologicals")){
window.add(new
Pathologicals(window,ClinicalFolder.this,false));
}
//aggiugere tutte le finestre da aprire
}
/*
*
* AGGIUNGE AL MENU IL PULSANTE "NEW"
*
*/
public void addNewMenu(Menu menu){
Item delete = new Item("New");
delete.setIcon("leaf.gif");
delete.addListener(new BaseItemListenerAdapter(){
public void onClick(BaseItem item, EventObject e){
//MessageBox.alert("new test ok");
Window windowNew=new Window();
windowNew.setDraggable(true);
windowNew.setPlain(true);
windowNew.setModal(true);
windowNew.removeAll();
selectNewWindow(windowNew);
windowNew.show();
}
});
menu.addItem(delete);
}
/*
*
* AGGIUNGE AL MENU IL PULSANTE "MODIFY"
*
*/
public void addModifyMenu(Menu menu){
127
Appendice
–
Codice
Sorgente
Item modify = new Item("Modify");
modify.setIcon("modify.gif");
modify.addListener(new BaseItemListenerAdapter(){
public void onClick(BaseItem item, EventObject e){
Window windowModify=new Window();
windowModify.setDraggable(true);
windowModify.setPlain(true);
windowModify.setModal(true);
windowModify.removeAll();
selectModifyWindow(windowModify);
windowModify.setResizable(false);
windowModify.show();
}
});
menu.addItem(modify);
}
/*
*
* AGGIUNGE AL MENU IL PULSANTE "DELETE"
*
*/
public void addDeleteMenu(Menu menu){
Item delete = new Item("Delete");
delete.setIcon("delete.gif");
delete.addListener(new BaseItemListenerAdapter(){
public void onClick(BaseItem item, EventObject e){
final ClinicalFolderRSAsync delete =
(ClinicalFolderRSAsync) GWT.create(ClinicalFolderRS.class); //crea il
servizo
ServiceDefTarget endpoint =
(ServiceDefTarget) delete;
endpoint.setServiceEntryPoint(GWT.getModuleBaseURL() +
"ClinicalFolderRS");
final AsyncCallback callback = new
AsyncCallback() {
public void onSuccess(Object
result) {
MessageBox.alert(tabPanel.getActiveTab().getTitle()+" deleted
!!!!");
String
tabIdRemove=tabPanel.getActiveTab().getId();
tabPanel.remove(tabIdRemove);
anamnesis.reload();
MessageBox.alert("Deleted");
}
public void onFailure(Throwable
caught) {
System.out.println("errore
nel delete");
}
128
Appendice
–
Codice
Sorgente
};
String message="You are deleting
"+tabPanel.getActiveTab().getTitle()+". Continue ?";
final String idSelected=idFiglio;
MessageBox.confirm("Confirm",
message,
new MessageBox.ConfirmCallback() {
public void execute(String btnID) {
if (btnID.equals("yes"))
delete.delete(idSelected,callback);
}
});
}
});
menu.addItem(delete);
}
/*
*
* AGGIUNGE AL MENU IL PULSANTE "REFRESH"
*
*/
public void addRefreshMenu(Menu menu){
Item refresh = new Item("Refresh");
refresh.setIcon("refresh.gif");
refresh.addListener(new BaseItemListenerAdapter(){
public void onClick(BaseItem item, EventObject e){
refreshPage();
reloadTree();
}
});
menu.addItem(refresh);
}
/*
* restituisce la pagine di visualizzazione dell'help
*/
public String getHelp() {
String help = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML
1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1transitional.dtd\">" +
"<html><head><title>HELP: Patient Clinical
Folder</title></head>" +
"<body><h2 align='center' style='color: red; fontsize:17px;'>WELCOME IN THE PATIENT CLINICAL FOLDER</h2>" +
"<br><p>Here you can find 3 different categories:
<b>PATIENT PROFILE</b>, <b>ANAMNESIS</b> and <b>PATIENT CLINICAL
PROBLEMS</b>.</p><br>" +
"<a href=\"tree.html\"
129
Appendice
–
Codice
Sorgente
target=\"_blank\"><b>Tree</b></a> categories:<ul>" +
"<li><dt style='color: darkblue;'><a
href=\"profile.html\" target=\"_blank\"><b>PATIENT
PROFILE</b></a></dt><dd>It contains the patient data.</dd></li>" +
"<li><dt style='color: darkblue;'><a
href=\"anamnesis.html\"
target=\"_blank\"><b>ANAMNESIS</b></a></dt><dd>It contains other data
linked to the patient and also the patient relatives.</dd></li>" +
"<li><dt style='color: darkblue;'><a ";
if (type.equals("requester")){
help+= "href=\"clinical.html\" ";
}
else {
help+= "href=\"clinicalD.html\" ";
}
help+="target=\"_blank\"><b>PATIENT CLINICAL
PROBLEMS</b></a></dt><dd>It contains the problems which need to be
sent to doctors for a report.</dd></li></ul>" +
"<br><p>Do you require explanations of
the buttons? <a href=\"buttons.html\" target=\"_blank\"><b>Click
here</b></a>.</p>" +
"</body></html>";
return help;
}
/*
*
* Mostra il menu quando si clicca con il destro sul tab
* Puo effettuare la chiusura del tab o di tutti gli altri tab
*
*/
private void showRightMenu(final Panel tab, EventObject e) {
if (rightClickMenu == null) {
rightClickMenu = new Menu();
Item close = new Item("Close This Tab");
close.setId("close-tab-item");
close.addListener(new
BaseItemListenerAdapter() {
public void onClick(BaseItem item,
EventObject e) {
tabPanel.remove(tabPanel.getActiveTab());
}
});
rightClickMenu.addItem(close);
rightClickMenu.addSeparator();
Item closeOthers = new Item("Close Others
Tabs");
closeOthers.setId("close-others-item");
closeOthers.addListener(new
BaseItemListenerAdapter() {
public void onClick(BaseItem item,
EventObject e) {
Component[] items =
tabPanel.getItems();
for (int i = 0; i < items.length;
i++) {
Component component = items[i];
if
(!component.getId().equals(tabPanel.getActiveTab().getId())) {
tabPanel.remove(component);
130
Appendice
–
Codice
Sorgente
}
}
}
});
rightClickMenu.addItem(closeOthers);
rightClickMenu.addSeparator();
Item closeAll = new Item("Close All tabs");
closeAll.setId("close-all-item");
closeAll.addListener(new
BaseItemListenerAdapter() {
public void onClick(BaseItem item,
EventObject e) {
MessageBox.confirm("Confirm", "Close
all tabs:<br>are you sure ?",
new
MessageBox.ConfirmCallback() {
public void
execute(String btnID) {
if
(btnID.equals("yes"))
tabPanel.removeAll(true);
//tabPanel.removeAll();
}
});
}
});
rightClickMenu.addItem(closeAll);
}
BaseItem closeOthers =
rightClickMenu.getItem("close-others-item");
if (tabPanel.getItems().length == 1) {
closeOthers.disable();
} else {
closeOthers.enable();
}
BaseItem closeAll =
rightClickMenu.getItem("close-all-item");
if (tabPanel.getItems().length == 1) {
closeAll.disable();
} else {
closeAll.enable();
}
rightClickMenu.showAt(e.getXY());
}
/*
* metodo per settare id del nodo/tab selezionato tramite il
click sull'albero
*
*/
public void setIdSelected(final TreeNode node){
ClinicalFolderRSAsync selected = (ClinicalFolderRSAsync)
GWT.create(ClinicalFolderRS.class); //crea il servizo
ServiceDefTarget endpoint = (ServiceDefTarget) selected;
131
Appendice
–
Codice
Sorgente
endpoint.setServiceEntryPoint(GWT.getModuleBaseURL() +
"ClinicalFolderRS");
AsyncCallback callback = new AsyncCallback() {
public void onSuccess(Object result) {
addTabChild(node); //aggiunge un tab
figlio
}
public void onFailure(Throwable caught) {
MessageBox.alert("error");
}
};
//VERIFICA ID FIGLI e SETTA L'ID SULLA SESSIONE
selected.setId(idFiglio.substring(1), callback);
}
/*
* metodo per settare id del nodo/tab selezionato
*
*/
public void setIdSelected(){
ClinicalFolderRSAsync selected = (ClinicalFolderRSAsync)
GWT.create(ClinicalFolderRS.class); //crea il servizo
ServiceDefTarget endpoint = (ServiceDefTarget) selected;
endpoint.setServiceEntryPoint(GWT.getModuleBaseURL() +
"ClinicalFolderRS");
AsyncCallback callback = new AsyncCallback() {
public void onSuccess(Object result) {
//addTabChild(); //aggiunge un tab figlio
}
public void onFailure(Throwable caught) {
MessageBox.alert("error");
}
};
//VERIFICA ID FIGLI e SETTA L'ID SULLA SESSIONE
selected.setId(idFiglio.substring(1), callback);
}
/*
* Ricarica la pagina AnamnesisView tramite un metodo
contenuto in tale pagina
*/
public void refreshPage(){
AnamnesisView.setLabel();
window.getEl().mask("Loading", "x-mask-loading");
Timer timer = new Timer() {
public void run() {
132
Appendice
–
Codice
Sorgente
window.getEl().unmask();
}
};
timer.schedule(1000);
}
/*
* SETTA L'EVENTO DA VISUALIZZARE
*/
public void setProblem(String type){
if (!tabPanel.hasItem("clinicalProblem")){
//tab del ramo Patient Profile
final Panel tabPatientProfile = new Panel();
tabPatientProfile.setTitle("Patient Problem");
tabPatientProfile.setId("clinicalProblem");
tabPatientProfile.setBaseCls("gwt-problems");
tabPatientProfile.setAutoScroll(true);
tabPatientProfile.setClosable(true);
if (type.equalsIgnoreCase("requester"))
tabPatientProfile.add(new
PatientClinicalProblem());
else
tabPatientProfile.add(new
ViewVisitsEvent(id_event,patient,id_patient));
tabPanel.add(tabPatientProfile); //aggiunge il
pannello "tab1" al TabPanel "tabPanel"
tabPanel.activate("clinicalProblem");
}
else{
tabPanel.activate("clinicalProblem");
}
}
/*
*
* SETTA L'EVENTO
*
*/
public void setDataDoc(String id_event1, String patient1,
String id_patient1)
{
id_event=id_event1;
patient=patient1;
id_patient=id_patient1;
}
}
133
Appendice
–
Codice
Sorgente
Clinical Folder – Lato Server
public class ClinicalFolderRSImpl extends RemoteServiceServlet
implements ClinicalFolderRS {
public ArrayList view(){
HttpServletRequest request = this.getThreadLocalRequest();
HttpSession session = request.getSession();
PatientSession currentPatient=(PatientSession)
session.getAttribute("ps");
UserSession
currentUser=(UserSession)session.getAttribute("us");
String name=currentPatient.getName()+"
"+currentPatient.getSurname();
String type=currentUser.getType();
ArrayList result=new ArrayList();
result.add(name);
result.add(type);
return result;
}
public void setId(String id){
HttpServletRequest request = this.getThreadLocalRequest();
HttpSession session = request.getSession();
session.setAttribute("id", id);
//
System.out.println("id="+session.getAttribute("id").toString());
}
public void delete(String idSelected){
HttpServletRequest request = this.getThreadLocalRequest();
HttpSession session = request.getSession();
PatientSession currentPatient=(PatientSession)
session.getAttribute("ps");
int patientId=currentPatient.getId();
String id=(String) session.getAttribute("id");
//System.out.println("nel delete:"+id);
String table=new String();
if (idSelected.substring(0, 1).equals("1"))
table="anamnesis_allergologies";
if (idSelected.substring(0, 1).equals("2"))
table="anamnesis_family_pathologies";
if (idSelected.substring(0, 1).equals("3"))
table="anamnesis_pathologicals";
String query="delete from "+table+" where id="+id;
if (idSelected.equals("familiars"))
query="delete from anamnesis_familiars where
patient_id="+patientId;
if (idSelected.equals("physiologicals"))
query="delete from anamnesis_physiologicals where
patient_id="+patientId;
Database conn = new
Database("mironjava","mironjava","abppt_5");
conn.connetti();
System.out.println(query);
try{
134
Appendice
–
Codice
Sorgente
conn.delete(query);
}
catch (Exception e) {
System.out.println("errore nel delete:
"+e.getMessage()+e.getCause());
}
finally{
conn.closeConn();
}
}
}
Allergology – Lato Client
public class Allergology extends Composite {
public ArrayList names=new ArrayList();
public int k=0;
public String allergies[][];
public TextArea note;
public ComboBox typology;
public DateField bDate, eDate;
final AbsolutePanel absolutePanel;
public Allergology(final Window window, final ClinicalFolder
clinicalFolder,final boolean modifyStatus) {
window.setSize("700", "350");
absolutePanel = new AbsolutePanel();
initWidget(absolutePanel);
absolutePanel.setSize("700", "350");
absolutePanel.setStylePrimaryName("gwt-box1");
absolutePanel.setVisible(true);
final FieldSet fieldSet = new FieldSet("Allergy
description");
fieldSet.setSize("641px", "100px");
fieldSet.setPaddings(10);
typology = new ComboBox("Typology");
typology.setDisplayField("typology");
typology.setMode(ComboBox.LOCAL);
typology.setTriggerAction(ComboBox.ALL);
typology.setTypeAhead(true);
typology.setSelectOnFocus(true);
typology.setWidth(150);
typology.setAllowBlank(false); //non puo essere
vuoto
typology.setForceSelection(true);
135
Appendice
–
Codice
Sorgente
fieldSet.add(typology);
note = new TextArea("Note");
note.setSize("465", "100");
fieldSet.add(note);
bDate = new DateField("Beginning date",
"bdate", 150);
bDate.setFormat("Y-m-d");
fieldSet.add(bDate);
eDate = new DateField("Ending date", "edate",
150);
eDate.setFormat("Y-m-d");
fieldSet.add(eDate);
absolutePanel.add(fieldSet, 20, 30);
final Button saveButton = new Button("Save");
absolutePanel.add(saveButton, 320, 292);
saveButton.addListener(new
ButtonListenerAdapter() {
public void onClick(final Button button,
final EventObject e) {
if(modifyStatus)
startModify(window,clinicalFolder);
else
startNew(window,clinicalFolder);
}
});
saveButton.setSize("100px", "20px");
startView(modifyStatus);
}
/*
* METODI ESTERNI
*/
/*
* MODIFICA
*/
public void startModify(final Window window, final ClinicalFolder
clinicalFolder){
boolean dateStatus=true;
if (!eDate.getValueAsString().equals("") &&
(eDate.getValue()).before(bDate.getValue())){
eDate.markInvalid("Date invalid:<br>ending date is
before beginning date");
136
Appendice
–
Codice
Sorgente
dateStatus=false;
}
final AllergologyRSAsync modify = (AllergologyRSAsync)
GWT.create(AllergologyRS.class); //crea il servizo
ServiceDefTarget endpoint = (ServiceDefTarget)
modify;
endpoint.setServiceEntryPoint(GWT.getModuleBaseURL()
+ "AllergologyRS");
final AsyncCallback callback = new AsyncCallback() {
public void onSuccess(Object result) {
Panel
tab=clinicalFolder.tabPanel.getActiveTab();
Panel newTab = new Panel();
newTab.setClosable(true);
newTab.setAutoScroll(true);
newTab.setBaseCls("gwt-sub");
newTab.setTitle(typology.getText());
newTab.add(new
AllergologyView(clinicalFolder));
Toolbar
toolbar=clinicalFolder.createToolbar();
newTab.setTopToolbar(toolbar);
String id=tab.getId();
clinicalFolder.idFiglio=id.substring(6,id.length());
MessageBox.alert("Changes saved
successfully");
clinicalFolder.reloadTree(); //carica
l'albero
clinicalFolder.updateTab(tab,newTab);
//aggiorna i tab
window.close();
}
public void onFailure(Throwable caught) {
MessageBox.alert(caught.getMessage()+caught.getCause()+caught.getStack
Trace());
}
};
if (typology.isValid() && bDate.isValid() &&
eDate.isValid() && dateStatus){
MessageBox.confirm("Confirm", "Confirm
changes ?",
new
MessageBox.ConfirmCallback() {
public void execute(String btnID) {
if
(btnID.equals("yes"))
modify.modify(typology.getText(), note.getText(),
bDate.getValue(), eDate.getValue(), callback);
}
});
137
Appendice
–
Codice
Sorgente
}
}
/*
* CARICAMENTO DATI PAGINA
*/
public void startView(final boolean modifyStatus){
//al caricamento della pagia viene effettuata la callback
AllergologyRSAsync view = (AllergologyRSAsync)
GWT.create(AllergologyRS.class); //crea il servizo
ServiceDefTarget endpoint = (ServiceDefTarget) view;
endpoint.setServiceEntryPoint(GWT.getModuleBaseURL() +
"AllergologyRS");
AsyncCallback callback = new AsyncCallback() {
public void onSuccess(Object result) {
ArrayList text=(ArrayList) result;
int i=0;
if (modifyStatus){
if (text.get(i)!=null)
typology.setValue(text.get(i++).toString());
else i++;
if (text.get(i)!=null)
note.setValue(text.get(i++).toString());
else i++;
if (text.get(i)!=null)
bDate.setValue(text.get(i++).toString());
else i++;
if (text.get(i)!=null)
eDate.setValue(text.get(i++).toString());
else i++;
}
names=(ArrayList) text.get(4);
k=names.size();
allergies=new String[k][1];
for (int j=0;j< k;j++){
allergies[j][0]=names.get(j).toString();
}
final Store store = new SimpleStore(new
String[]{"typology"}, allergies);
store.load();
typology.setStore(store);
}
public void onFailure(Throwable caught) {
MessageBox.alert(caught.getMessage()+caught.getCause()+caught.getStack
Trace());
}
};
view.view(callback);
138
Appendice
–
Codice
Sorgente
}
/*
* INSERIMENTO
*/
public void startNew(final Window window,final ClinicalFolder
clinicalFolder){
boolean dateStatus=true;
if (!eDate.getValueAsString().equals("") &&
(eDate.getValue()).before(bDate.getValue())){
eDate.markInvalid("Date invalid:<br>ending date
is before beginning date");
dateStatus=false;
}
final AllergologyRSAsync insert = (AllergologyRSAsync)
GWT.create(AllergologyRS.class); //crea il servizo
ServiceDefTarget endpoint = (ServiceDefTarget) insert;
endpoint.setServiceEntryPoint(GWT.getModuleBaseURL() +
"AllergologyRS");
final AsyncCallback callback = new AsyncCallback() {
public void onSuccess(Object result) {
MessageBox.alert("Inserted");
clinicalFolder.reloadTree(); //carica l'albero
clinicalFolder.refreshPage();
window.close();
}
public void onFailure(Throwable caught) {
MessageBox.alert(caught.getMessage()+caught.getCause()+caught.getStack
Trace());
}
};
if (typology.isValid() && bDate.isValid() &&
eDate.isValid() && dateStatus){
MessageBox.confirm("Confirm", "Confirm date ?",
new MessageBox.ConfirmCallback() {
public void execute(String btnID) {
if (btnID.equals("yes"))
insert.insert(typology.getText(),
note.getText(), bDate.getValue(), eDate.getValue(), callback);
}
});
}
}
}
139
Appendice
–
Codice
Sorgente
Allergology – Lato Server
public class AllergologyRSImpl extends RemoteServiceServlet implements
AllergologyRS {
public boolean modify(String typology, String note, Date bDate,
Date eDate){
HttpServletRequest request = this.getThreadLocalRequest();
HttpSession session = request.getSession();
//UserSession currentPatient=(UserSession)
session.getAttribute("us");
String id=(String) session.getAttribute("id"); // deve
essere settata la sessione nelle pagina di visualizzazione pazienti
Database conn =
new
Database("mironjava","mironjava","abppt_5");
conn.connetti();
String allergyId=new String();
String query="SELECT id FROM allergies where
name=\""+typology+"\";";
try{
conn.query(query);
conn.getResult().first();
allergyId=conn.getResult().getString("id");
}
catch (Exception e) {
System.out.println("Eccezione: "+e.getMessage());
return false;
}
Calendar bCal=new GregorianCalendar();
Calendar eCal=new GregorianCalendar();
query="update anamnesis_allergologies set ";
query+=" notes=\""+note+"\",";
if (bDate!=null){
bCal.setTime(bDate);
int bY=bCal.get(Calendar.YEAR);
int bM=bCal.get(Calendar.MONTH)+1;
int bD=bCal.get(Calendar.DATE);
query+=" beginning_date=\""+bY+"-"+bM+"-"+bD+"\",";
}
else query+=" beginning_date=null,";
if (eDate!=null){
eCal.setTime(eDate);
int eY=eCal.get(Calendar.YEAR);
int eM=eCal.get(Calendar.MONTH)+1;
int eD=eCal.get(Calendar.DATE);
query+=" ending_date=\""+eY+"-"+eM+"-"+eD+"\",";
}
else query+=" ending_date=null,";
query+=" allergy_id=\""+allergyId+"\"";
query+=" where id="+id+";";
140
Appendice
–
Codice
Sorgente
try {
conn.insert(query);
}
catch (Exception e) {
System.out.println("Eccezione:
"+e.getMessage());
return false;
}
finally{
conn.closeConn();
}
return true;
}
public ArrayList view() {
//sessione
HttpServletRequest request = this.getThreadLocalRequest();
HttpSession session = request.getSession();
//UserSession currentPatient=(UserSession)
session.getAttribute("us");
String id=(String) session.getAttribute("id");
Database conn =
new
Database("mironjava","mironjava","abppt_5");
conn.connetti();
String query="SELECT name FROM allergies";
ArrayList names=new ArrayList();
try {
conn.query(query);
while(conn.getResult().next())
names.add(conn.getResult().getString("name"));
}
catch (Exception e) {
System.out.println("eeee2222"+e.getMessage()+e.getCause()+e.getS
tackTrace());
String mess="errore: ";
mess+="\n\nLOG DATABASE: "+conn.getLog();
System.out.println(mess);
String [] error={mess};
ArrayList ret_err= new ArrayList();
for (int i=0;i<=error.length;i++)
ret_err.add(i, error[i]);
return ret_err;
}
query="SELECT * FROM anamnesis_allergologies, allergies";
query+=" WHERE allergy_id=allergies.id and
anamnesis_allergologies.id="+id+";";
String name=new String();
String note=new String();
String bDate=new String();
String eDate=new String();
ArrayList values=new ArrayList();
try {
conn.query(query);
141
Appendice
–
Codice
Sorgente
if(conn.getResult().first()){
name=conn.getResult().getString("name");
note=conn.getResult().getString("notes");
bDate=conn.getResult().getString("beginning_date");
eDate=conn.getResult().getString("ending_date");
}
values.add(name);
values.add(note);
values.add(bDate);
values.add(eDate);
values.add(names); //nomi di tutte le allergie
**array list**
System.out.println("values
0:"+values.get(0).toString());
System.out.println("names:"+names.get(0).toString());
}
catch (Exception e) {
System.out.println("errore nel
view:"+e.getMessage()+e.getCause()+e.getStackTrace());
String mess="errore: ";
mess+="\n\nLOG DATABASE: "+conn.getLog();
System.out.println(mess);
String [] error={mess};
ArrayList ret_err= new ArrayList();
for (int i=0;i<=error.length;i++)
ret_err.add(i, error[i]);
return ret_err;
}
finally{
conn.closeConn();
}
return values;
}
public boolean insert(String typology, String note, Date bDate,
Date eDate){
HttpServletRequest request = this.getThreadLocalRequest();
HttpSession session = request.getSession();
PatientSession currentPatient=(PatientSession)
session.getAttribute("ps");
int patientId=currentPatient.getId();
Database conn =
new
Database("mironjava","mironjava","abppt_5");
conn.connetti();
String allergyId=new String();
String query="SELECT id FROM allergies where
name=\""+typology+"\";";
try{
conn.query(query);
conn.getResult().first();
allergyId=conn.getResult().getString("id");
}
catch (Exception e) {
142
Appendice
–
Codice
Sorgente
System.out.println("Eccezione: "+e.getMessage());
return false;
}
query="insert into anamnesis_allergologies values ";
query+="(null,"+patientId+","+allergyId+",\""+note+"\",";
Calendar bCal=new GregorianCalendar();
Calendar eCal=new GregorianCalendar();
if (bDate!=null){
bCal.setTime(bDate);
int bY=bCal.get(Calendar.YEAR);
int bM=bCal.get(Calendar.MONTH)+1;
int bD=bCal.get(Calendar.DATE);
query+=" \""+bY+"-"+bM+"-"+bD+"\",";
}
else query+=" null,";
if (eDate!=null){
eCal.setTime(eDate);
int eY=eCal.get(Calendar.YEAR);
int eM=eCal.get(Calendar.MONTH)+1;
int eD=eCal.get(Calendar.DATE);
query+=" \""+eY+"-"+eM+"-"+eD+"\")";
}
else query+=" null)";
System.out.println(query);
try{
conn.insert(query);
}
catch (Exception e) {
System.out.println("Eccezione: "+e.getMessage());
return false;
}
finally{
conn.closeConn();
}
return true;
}
}
143
BIBLIOGRAFIA
• Wikipedia, http://www.wikipedia.org : enciclopedia libera scritta
dagli utenti del web;
• http://code.google.com/webtoolkit/ : sito ufficiale di Google Web
Tooolkit;
• http://gwt-ext.com/ : sito ufficiale librerie GWT-Ext;
• http://tomcat.apache.org/ : sito ufficiale di Apache Tomcat;
• http://javascript.html.it/
:
sito
da
cui
sono
state
prelevate
informazioni riguardo JavaScript e AJAX;
• H.M. Deitel, P.J. Deitel, “Java – Fondamenti di Programmazione”:
consultazioni informazioni di base sul Java;
• H.M. Deitel, P.J. Deitel, “Java
– Tecniche Avanzate di
Programmazione”: consultazione informazioni avanzate sul Java e
sui Servelts.
144

Scarica