Telemedicine

Transcript

Telemedicine
UNIVERSITA’ POLITECNICA DELLE MARCHE
FACOLTA’ DI INGEGNERIA
Corso di Laurea in Ingegneria Elettronica
Dipartimento di Elettronica, Intelligenza Artificiale e Telecomunicazioni
UN’ ARCHITETTURA SOFTWARE COMPLETA
PER TELECONSULTO E TELEREFERTAZIONE:
PROGETTO DI APPLICAZIONI SICURE LATO CLIENT
Tesi di Laurea di:
Roberto Di Rosa
Relatore:
Prof. Aldo Franco Dragoni
Correlatoei:
Prof. Paolo Puliti
Anno Accademico 2004-2005
INDICE
Introduzione ..........................................................................
Capitolo 1. Telemedicina ...................................................... 1
1.1 Introduzione ................................................................... 2
1.2 Applicazioni .................................................................... 4
1.2.1 Vantaggi ................................................................... 5
1.2.2 Problemi.................................................................... 5
1.3 Stato dell’Arte................................................................. 6
1.4 Progetti dell’ ASUR Marche zona 7 ..................................... 8
1.4.1 Sistema di teleconsulto ospedale di Osimo con stazioni
fisse e stazioni mobili .................................................. 8
1.4.2 Assistente Virtuale .................................................... 11
1.4.3 Delocalizzazione della Refertazione Diagnostica............. 12
Capitolo 2. Progetto MiRo................................................... 14
2.1 Finalità ........................................................................ 15
2.2 Architettura generale ..................................................... 17
2.2.1 Repository ............................................................... 19
2.2.2 Laboratorio .............................................................. 21
2.2.3 Medico .................................................................... 22
2.3 Soluzioni tecniche.......................................................... 26
2.3.1 Comunicazione sicura................................................ 27
2.3.2 Messaggi SOAP ........................................................ 29
-I-
Capitolo 3. Mutuo Riconoscimento e Interfacce Grafiche....30
3.1 Laboratorio................................................................... 31
3.1.1 Web Service laboratorio............................................. 31
3.1.2 Mutuo Riconoscimento............................................... 32
3.1.3 Interfacce grafiche.................................................... 32
3.2 Medico ......................................................................... 36
3.2.1 Mutuo Riconoscimento............................................... 36
3.2.2 Interfacce grafiche.................................................... 37
3.2.3 Firma del referto ...................................................... 39
Capitolo 4. Tecnologie Software ......................................... 42
4.1 Java Platform................................................................ 43
4.1.1 Java Server Pages .................................................... 46
4.2 Apache Tomcat ............................................................. 57
4.2.1 Comunicazione SSL................................................... 71
4.3 Strumenti di Sviluppo ..................................................... 84
4.3.1 Apache Struts .......................................................... 84
Capitolo 5. Crittografia A Chiave Pubblica .......................... 89
5.1 Crittografia ................................................................... 91
5.1.1 Introduzione ............................................................ 91
5.1.2 Crittografia a chiave simmetrica ................................. 94
5.1.3 Sistemi a crittografia a chiave pubblica ........................ 96
5.2 La Firma Digitale ........................................................... 99
5.2.1 Algoritmo RSA........................................................ 104
5.2.2 Algoritmo SHA-1 .................................................... 106
5.3 Certificati elettronici..................................................... 108
5.3.1 Standard X.509 per i certificati ................................. 110
5.3.2 Necessità di coppie di chiavi distinte per cifratura
e firma.................................................................. 112
5.4 Infrastruttura a chiave pubblica (PKI)............................. 117
5.4.1 Requisiti di una PKI................................................. 121
5.5 Gestione dei certificati.................................................. 123
5.5.1 Ciclo di vita dei certificati ......................................... 123
5.5.2 La gestione delle chiavi ........................................... 125
5.5.3 La revoca di un certificato ........................................ 126
5.5.4 I cammini di certificazione ....................................... 130
- II -
Capitolo 6. Conclusioni..................................................... 133
Appendice A. Codice sorgente .......................................... 146
A.1 Client Application ........................................................ 148
A.2 Web Service Client. ..................................................... 178
A.3 Common Library...........................................................207
Bibliografia ...................................................................... 224
- III -
INTRODUZIONE
Con il continuo sviluppo tecnologico
con l’ avvento dei
Digital Data e con la larga banda si sente forte la necessità
di
ristrutturare
l’intero
sistema
sanitario
nazionale
spingendosi verso le nuove frontiere della Telemedicina.
Il progetto MiRo, nasce, proprio da questo
bisogno e
dalla collaborazione tra ASUR Marche zona 7 di Ancona e l’
Università Politecnica delle Marche.
Il primo passo fatto è stato analizzare il significato del
termine Telemedicina, realizzando uno stato dell’ arte del
sistema
sanitario
nazionale.
Successivamente
si
è
approfondito uno dei settori di maggior interesse (la
teleradiologia) pensando e producendo un architettura
software
“flessibile”
completa
per
teleconsulto
e
teleassistenza.
Nei
prossimi
telemedicina,
capitoli
facendo
si
inquadrerà
particolare
il
concetto
riferimento
di
alle
problematiche delle aziende sanitarie locali (in particolare
della Asur di Ancona); successivamente si passerà ad una
descrizione del progetto MiRo e del suo funzionamento in
maniera dettagliata .
- IV -
CAP. 1 - TELEMEDICINA
CAPITOLO 1
TELEMEDICINA
Introduzione al concetto di telemedicina, stato dell’
arte
della
situazione
sanitaria
italiana
e
approfondimento dei progetti dell’ ASUR Marche
zona 7.
1.1 Introduzione
1.2 Applicazioni
1.2.1 Vantaggi
1.2.2 Problemi
1.3 Stato dell’Arte
1.4 Progetti dell’ASUR
1.4.1 Sistema di teleconsulto ospedale di Osimo
con stazioni fisse e stazioni mobili
1.4.2 Assistente Virtuale
1.4.3 Delocalizzazione della Refertazione
Diagnostica
-1-
CAP. 1 - TELEMEDICINA
1.1 INTRODUZIONE
Una definizione della Telemedicina che ha riscosso un
notevole
successo
è
la
seguente:
la
Telemedicina
rappresenta l’erogazione di servizi sanitari, laddove la
distanza
rappresenti
professionisti
un
fattore
nell’assistenza
critico
sanitaria
da
che
parte
di
utilizzino
tecnologie dell’informazione e della comunicazione per lo
scambio
di
trattamento
informazioni
e
la
rilevanti,
prevenzione
l’educazione
continuativa
nell’interesse
del
per
delle
degli
miglioramento
la
diagnosi,
patologie
e
operatori
della
il
per
sanitari,
salute
e
delle
comunità assistite.
La
Telemedicina
telecomunicazione
per
utilizza
erogare
le
tecnologie
assistenza
della
sanitaria
specialistica, spesso a notevoli distanze, con la possibilità di
contenere i costi delle prestazioni.
Questo avviene in special modo quando l’Assistenza
Sanitaria è rivolta ad aree isolate o comunque dove non sia
disponibile direttamente la prestazione specialistica del
medico.
La Telemedicina consente di conseguire notevoli benefici
sia per erogatori di assistenza remota, sia naturalmente,
per gli utenti dei servizi, siano essi pazienti o operatori
sanitari.
-2-
CAP. 1 - TELEMEDICINA
Lo sviluppo e l’applicazione della Telemedicina richiede
significativi expertise nei settori delle telecomunicazioni,
delle
erogazioni
dei
servizi
sanitari
e
dell’information
tecnology and comunications.
L’applicazione della Telemedicina ben si presta ad un
opera di cooperazione fra i paesi dotati di maggiori
tecnologie e quelli ancora in via di sviluppo.
Fig. 1.1 – Telemedicina
-3-
CAP. 1 - TELEMEDICINA
1.2 APPLICAZIONI
Il concetto di telemedicina non significa dunque soltanto
“medicina praticata a distanza“, ma include tutti quegli
aspetti legati all’ assistenza sanitaria in senso lato. Una
serie di nuovi concetti sono ora riferiti alla telemedicina;
due di questi sono e-health e tele-health(tele assistenza).
La telemedicina/teleassistenza può essere applicata in
vari modi in tutti i servizi sanitari; può facilitare e
razionalizzare
la
comunicazione
e
lo
scambio
di
informazioni: tra servizi di primaria assistenza e gli ospedali
, tra ospedali diversi, tra ospedali e i laboratori, tra i servizi
di
riabilitazione
telemedicina
e
le
riguarda
organizzazioni
anche
la
paramediche.
direzione
La
e
l’amministrazione dell’unità sanitarie locali, i pazienti e i
loro familiari.
1.2.1 Vantaggi
L’ avvento dell’ informatica medica e la conseguente
introduzione
di
nuove
tecnologie
nell’ambito
sanitario
hanno portato e porteranno notevoli vantaggi sia per i
pazienti che per il personale medico.
L’ introduzione della telemedicina permette :
-4-
CAP. 1 - TELEMEDICINA
• Diagnosi e cure più rapide
• Minor numero di spostamenti sia del personale
medico che dei pazienti
• Riduzione dei costi per personale (compreso quello
di emergenza)
• Comunicazioni più veloci
• Aggiornamento
più
semplice
e
rapido
delle
informazioni riguardanti diagnosi e metodi di cura
• Miglior sostegno allo staff medico per la formazione
sia teorica che pratica
1.2.2 Problemi
In passato i costi per l’attrezzatura e le telecomunicazioni
sono stati troppo alti da permetterne
un introduzione su
larga scala, oggi tuttavia la situazione sotto questo punto di
vista
è
notevolmente
migliorata
il
vero
ostacolo
da
affrontare è cercare di introdurre metodi che favoriscano l’
accettazione e la comprensione da parte del personale
interessato, delle applicazioni di telemedicina/teleassistenza
nei servizi sanitari.
Bisogna sottolineare che l’introduzione della telemedicina
influenza i tradizionali metodi di lavoro, si vanno a
modificare i modelli di cooperazione, si creano nuove figure
lavorative e molto spesso sorgono problemi di distribuzione
dei costi e di investimenti delle risorse.
-5-
CAP. 1 - TELEMEDICINA
A
livello
mancanza
internazionale,
di
uniformità
ad
oggi,
si
uso
del
sull’
registra
concetto
una
di
telemedicina; tutto ciò rende impossibile la creazione di
standard che possano regolamentare tale disciplina.
1.3 STATO DELL’ARTE
Oggigiorno i sistemi sanitari mondiali stanno facendo
passi da gigante nell’utilizzo massiccio della telemedicina,
grazie soprattutto allo sviluppo di nuove tecnologie.
In ambito nazionale ogni regione si sta attrezzando nello
sviluppo di sistemi di informatica medica . Uno dei principali
progetti a livello nazionale è rappresentato da As.ter: un
sistema informativo-informatico per la gestione di tutte le
attività del territorio, sviluppato dalla USL 11 di Empoli.
As.Ter
integra,
con
l’ausilio
di
una
piattaforma
tecnologica innovativa, tutti gli applicativi ed i database
delle
attività
sanitarie
e
sociali
svolte
sul
territorio,
consentendo la rilevazione dei bisogni complessivi dei
cittadini, l’individuazione delle modalità e dei tempi di
risposta ai loro bisogni, la rilevazione dei costi; tutto ciò al
fine di pianificare e gestire le attività sociosanitarie sul
territorio in un ottica manageriale di costi/benefici.
Un altro progetto è stato proposto dal servizio sanitario
regionale emilia-romagna con il nome di SOLE . Esso è
finalizzato a realizzare una rete telematica di collegamento
-6-
CAP. 1 - TELEMEDICINA
tra i servizi ospedalieri e i servizi territoriali per agevolare la
comunicazione tra operatori sanitari e, di conseguenza,
agevolare l'erogazione dei servizi con importanti e positive
ricadute sulla continuità assistenziale e sulla semplificazione
dell’accesso ai servizi per il cittadino.
-7-
CAP. 1 - TELEMEDICINA
1.4 PROGETTI DELL’ASUR
MARCHE ZONA 7
L’ ASUR della regione Marche zona 7 ha sviluppato una
serie di progetti che riguardano l’ ambito medico tra i quali
troviamo:
• Sistema di Teleconsulto ospedale di Osimo con
stazioni fisse e stazioni mobili
• Assistente Virtuale
• Delocalizzazione della refertazione diagnostica
1.4.1 Sistema
Osimo
di
con
teleconsulto
stazioni
ospedale
fisse
e
di
stazioni
mobili
La Telelettrocardiografia è stata la prima applicazione
derivate dalle esperienze aerospaziali sia americane che
russe. Lo sviluppo enorme in tutti i paesi industrializzati
della telefonia cellulare consente di erogare questo tipo di
servizio di Telerefertazione con una eccezionale capillarità
territoriale.
Il sistema è composto da un server situato presso
l’Ospedale di Osimo, le caratteristiche del server sono le
-8-
CAP. 1 - TELEMEDICINA
seguenti: Server Compaq Proliant ML 370 T, P3 1266 GB,
Cache 256 K ram 256 MB, 3 Hard Disk da 18 GB, il
software permette la connessione fino a 25 apparecchiature
in rete Ethernet.
E’
inoltre
composto
da
un
client
situato
presso
l’Ospedale di Osimo, le caratteristiche del client sono:
Compaq EVO D500 SFFP 4 – 1.5 GB Hard Disk da 20GB,
schede di rete CD Rom 48 per monitor 17 e stampante
laser HP 1200 e da tre stazioni fisse composte da tre
elettrocardiografi del tipo Archimed Base Plus il quale
consiste in un elettrocardiografo portatile per l’acquisizione
contemporanea di dodici derivazioni dotate di monitor Lcd
retroilluminato ad alta risoluzione di grandi dimensioni per
la visualizzazione di sei tracce Ecg, tastiera alfanumerica,
Driver per floppy da 3,5 e hard disk da un giga per la
memorizzazione
dei
tracciati.
L’elettrocardiografo
è
provvisto di varie uscite esterne, tra cui quattro seriali RS
232, una rete Ethernet per trasmissione e ricezione di
tracciati ecg con relativo referto e stampante Archimed
4240 termica formato A4.
Inoltre di una stazione mobile
composta da una valigetta AT 4 Gsm che è una 24 ore
completa di elettrocardiografo portatile computerizzata,
dotato di Display Lcd di grandi dimensioni che permette di
visualizzare contemporaneamente tre tracce ecg oltre una
stampante
per
l’acquisizione
contemporanea
di
dodici
derivazioni ecg in modalità automatica, l’apparecchio è
dotato di memoria interna per l’archiviazione di quaranta
-9-
CAP. 1 - TELEMEDICINA
ecg (10 secondi 12 derivazioni) fornita di cellulare Gsm
Dual Band con interfaccia per elettrocardiografo e cavi di
connessione
per
la
trasmissione
digitale
dell’ecg
alla
Centrale di Ascolto, funzione di viva voce per comunicare
con la Centrale di Ascolto.
Il Client è posto nella zona di controllo della Unità di
Terapia Critica del Dipartimento di Medicina Interna ove un
operatore è costantemente presente durante le ore del
giorno e della notte.
Le tre stazioni fisse sono al momento situate presso le
Unità di degenza mediche del Presidio Ospedaliero di Osimo
ed
una
presso
i
Poliambulatori
di
Camerano
situati
all’interno di una struttura residenziale per anziani con circa
80 degenti.
La stazione mobile viene al momento affidata agli
operatori della Emergenza Urgenza Territoriale che fanno
capo al Distretto Ancona Sud.
Fig. 1.2 – Telemedicina
- 10 -
CAP. 1 - TELEMEDICINA
1.4.2 Assistente Virtuale
E’ un progetto ancora in fase embrionale che ha come
obbiettivo quello di creare un assistente personale virtuale
che sia in grado di offrire ad ogni singolo utente un valido
appoggio in riferimento alla propria situazione clinica.
Fig. 1.3 – Interfaccia dell’assistente virtuale
- 11 -
CAP. 1 - TELEMEDICINA
1.4.3 Delocalizzazione
della
Refertazione
Diagnostica
Nell’ottica di capillarizzare l’offerta sanitaria così come
negli obiettivi della sanità regionale, può essere importante
pensare
ad
indipendenti
una
le
struttura
due
fasi
informatica
tipiche
della
che
renda
diagnostica:
l’esecuzione dell’esame e la sua refertazione. Infatti mentre
è possibile pensare di localizzare alcuni macchinari (di
basso costo) anche nei poliambulatori più piccoli, può
risultare sconveniente portare in questi poliambulatori
personale di alta specializzazione .
La struttura informatica che ci si propone di realizzare
in questa fase, poi potrà anche servire per altri scopi come
consulti medici oppure per fornire servizi (a pagamento) di
refertazione per altri enti.
Fig. 1.4 – Delocalizzazione diagnostica
- 12 -
CAP. 1 - TELEMEDICINA
Sostanzialmente un sistema
per la refertazione a
distanza altro non è che un repository di eventi sanitari con
relativo output dell’esame (ad esempio una radiografia, un
elettrocardiogramma, ……).
In questo repository gli enti periferici (poliambulatori
etc.) depositano gli output degli esami e prelevano i referti
mentre il centro di refertazione preleva gli output degli
esami ed inserisce i referti relativi.
Per mettere in piedi la procedura appena descritta è
indispensabile:
• Che tutti i partecipanti siano collegati ad una rete
intranet o internet
• Essere
collegati
ad
una
infrastruttura
PKI
funzionante
• Utilizzare un metodo di trasferimento sicuro
(SSL)
La nostra tesi nasce proprio come sviluppo a livello
software del progetto di delocalizzazione .
Nei prossimi capitoli si approfondirà il progetto MiRo,
sottolineando la sua grande flessibilità ed efficacia per i
sistemi di teleconsulto e telerefertazione.
- 13 -
CAP. 2 – PROGETTO MIRO
CAPITOLO 2
PROGETTO MIRO
Descrizione dell’ architettura del Progetto MiRo,
spiegazione del funzionamento delle varie parti del
sistema: repository, medico e laboratorio.
Soluzioni tecniche adottate.
2.1 Finalità
2.2 Architettura Generale
2.2.1 Repository
2.2.2 Laboratorio
2.2.3 Medico
2.3 Soluzioni Tecniche
2.3.1 Comunicazione sicura
2.3.2 Messaggi SOAP
- 14 -
CAP. 2 – PROGETTO MIRO
2.1 FINALITÀ
Il
progetto
MiRo
nasce
dalla
collaborazione
tra
l’Università Politecnica delle Marche con l’ azienda ASUR
Marche zona 7 di Ancona, come sviluppo del progetto che
l’ASUR
aveva
sulla
delocalizzazione
della
refertazione
diagnostica.
L’ obbiettivo del nostro progetto era quello fornire
all’azienda sanitaria locale, un prodotto flessibile che
implementasse un servizio di refertazione asincrono; cioè in
grado di separare non solo da un punto di vista temporale,
ma anche da quello spaziale, l’ esecuzione dell’ esame dalla
refertazione dello stesso.
Fig. 2.1 – Contesto di lavoro
- 15 -
CAP. 2 – PROGETTO MIRO
Tutto ciò doveva essere fatto garantendo un livello di
sicurezza e di affidabilità, del trattamento del dato clinico,
accettabile.
Lo scopo di MiRo è stato creare un applicazione software
completa
in
grado
di
gestire
l’
intero
telerefertazione e di teleconsulto.
Fig. 2.2 – Introduzione di Miro
- 16 -
processo
di
CAP. 2 – PROGETTO MIRO
2.2 ARCHITETTURA GENERALE
Il primo passo fatto nel progettare MiRo (così si chiama il
progetto) è stato cercare di capire come si dovesse
integrare con il sistema informativo sanitario già esistente;
la prima ipotesi semplificativa adottata è stata quella di
creare una piattaforma flessibile per lo sviluppo di servizi
sanitari che avesse un’ architettura orientata ai servizi.
Si è pensato di creare una struttura semplice, basata su
standard diffusi e riconosciuti, come Internet, in modo da
creare le basi per facilitare le applicazioni sia in ambito
sanitario a livello di personale medico che in futuro
direttamente ai cittadini.
MiRo si basa sul concetto di evento, questo aspetto
rappresenta
il
punto
focale
dell’
intero
sistema.
L’
effettuazione di un esame presso un laboratorio (qualsiasi,
di una qualunque struttura ospedaliera) e la conseguente
archiviazione del dato in forma digitale genera ciò che viene
chiamato evento.
L’ evento non è il dato clinico vero e proprio ma
rappresenta una sorta di meta-dato-clinico del dato digitale
prelevato in laboratorio. Esso consiste in una serie di
informazioni che riguardano il dato digitale prodotto dall’
evento come ad esempio: l’ unità erogante il dato, la data e
l’ ora dell’esame, la struttura che l’ha prodotto, il codice
- 17 -
CAP. 2 – PROGETTO MIRO
impegnativa, il link da dove si può scaricare il dato, lo stato
ecc….
Ogni evento quindi viene immagazzinato all’ interno di un
apposito raccoglitore, definito repository, che costituisce il
cuore del sistema e che contiene la definizione del legame
tra evento ed esame.
Qualsiasi esame che può essere memorizzato in forma
digitale può essere associato ad un evento, in questo modo
siamo riusciti a dare a MiRo una certa flessibilità ed
adattabilità che venivano richieste in fase di progettazione.
In figura è mostrata l’architettura generale di MiRo dove
si notano i tre attori principali del sistema:
• Repository
• Laboratories
• Doctors
Fig. 2.3 –Architettura generale di MiRO
- 18 -
CAP. 2 – PROGETTO MIRO
Il cuore del sistema è rappresentato dal Repository
centrale offerto da un azienda o da un ente erogante (vedi
ASUR), il quale si impegna nel corretto funzionamento dell’
intero sistema di refertazione e nella manutenzione dello
stesso.
A destra del repository troviamo il laboratorio, cioè la
struttura che usufruisce del servizio per generare gli eventi
dovuti all’ acquisizione dei dati digitali di un esame clinico.
A sinistra del repository si trova colui che scrive il referto
ossia il medico o un equipe di medici specializzati, i quali
pubblicano il proprio referto autenticandolo con la propria
firma digitale.
2.2.1 Repository
La struttura del sistema prevede la presenza di un
repository centrale, altro non è che un database relazionale
nel quale vengono memorizzati le informazioni relativi ai
dati digitali prodotti nei laboratori.
Un record di questo repository costituisce quello che noi
chiamiamo “evento” Fig. 2.4; l’ evento rappresenta una
sorta di meta-dato informativo riguardante il dato digitale
prodotto nei laboratori .
- 19 -
CAP. 2 – PROGETTO MIRO
Fig. 2.4 – Struttura Dati
Le informazioni che vengono registrate sono data e ora
dell’inserimento nella base dati, il tipo di esame eseguito e
il laboratorio in cui è stato effettuato, informazioni sulla
provenienza della richiesta di prestazione sanitaria e il
percorso (pathname) dove recuperare l’ esame o meglio il
dato digitale riguardante l’ esame vero e proprio. Dopo
lunghe fasi di consultazioni con l’ azienda sanitaria si è
ritenuto opportuno organizzare il record in questa maniera,
in modo da render semplici ed accessibili le informazioni
principali riguardanti un esame.
Da
notare
che
non
vengono
mai
registrate
le
informazioni relative al paziente, infatti il nostro primo
obbiettivo è quello di fornire un servizio di refertazione che
abbia la possibilità di concedere “second opinion”. Tuttavia
non viene concesso un servizio di diagnosi, per il quale
- 20 -
CAP. 2 – PROGETTO MIRO
sarebbe necessario un trattamento dei dati sensibili del
paziente. Tutto ciò rende molto flessibile la struttura
eliminando i problemi riguardanti la privacy.
2.2.2 Laboratorio
La seconda figura che viene presa in esame è il
laboratorio,
con
questo
termine
intendiamo
qualsiasi
struttura sanitaria abbia necessità di farsi refertare un
esame; potrebbe essere un laboratorio radiologico, analisi,
epidemiologico oppure un autoambulanza con apposita
apparecchiatura, una piattaforma petrolifera
(anche essa
con i giusti strumenti)ecc…. Noi chiameremo, in tutti i nostri
discorsi tutte queste unità con la definizione di laboratorio.
Il laboratorio apre un evento cioè una volta effettuato un
esame e ottenuto il dato digitale sia in maniera diretta o
tramite passaggi di discretizzazione, si collega al web
service dell’ ente fornitrice il servizio (nel nostro caso ASUR
Marche zona 7) e tramite un opportuna interfaccia inserisce
i dati relativi all’ esame fatto nel data base centrale. In
questo modo il dato digitale presente nel laboratorio
diventa accessibile e pronto per essere refertato da parte
degli altri attori di questo sistema, i dottori o meglio il
personale specializzato.
Una volta generato l’ evento (scrittura nel database
centrale), il laboratorio si pone in una posizione di
- 21 -
CAP. 2 – PROGETTO MIRO
monitoraggio,
ossia
controlla
tutte
le
varie
fasi
di
refertazione che l’ evento da lui generato subisce, fino a
che non ritiene soddisfatta la sua richiesta.
A questo punto il laboratorio dichiara chiuso l’ evento
così termina la fase di refertazione; solo chi ha inoltrato la
richiesta può terminare il processo di refertazione, così il
servizio è completo.
Tutto ciò garantisce e rispetta in pieno uno degli
obbiettivi principali del progetto MiRo la grande flessibilità e
adattabilità per ogni tipo di struttura dei servizi sanitari.
Fig. 2.5 – Flusso di operazioni Lab. vs Rep.
2.2.3 Medico
Una volta che il laboratorio apre l’ evento e quindi va ad
aggiungere un record al Repository centrale, effettua una
richiesta di refertazione all’ altra figura che compare nell’
- 22 -
CAP. 2 – PROGETTO MIRO
architettura di MiRo: i medici o per meglio dire il personale
specializzato.
Ogni medico, effettuando l’ accesso tramite un semplice
web browser (es Internet Explorer) accede al web service
centrale dove tramite opportune interfacce user friendly
verranno mostrati, solo gli eventi che ogni medico è in
grado di refertare, questo perché in generale noi stiamo
parlando di specialisti in particolari discipline mediche.
Fig. 2.6 – Flusso di operazioni Doc. vs Rep.
Ad ogni dottore viene visualizzata una form dove sono
presenti data e ora di inserzione nel database, il laboratorio
che l’ ha creata, lo stato dell’ esame( aperto, refertato,
chiuso)e infine il download ossia la possibilità di scaricarsi il
dato ottenuto in laboratorio sul proprio pc, per poi poter
visualizzarlo e conseguentemente refertarlo.
Quando il medico decide di refertare gli appare una form
dove può scrivere il suo referto e contemporaneamente può
leggere i referti emessi dagli altri medici, in questo modo si
- 23 -
CAP. 2 – PROGETTO MIRO
viene a creare un meccanismo definito “second opinion”
(uno degli obbiettivi di partenza del nostro lavoro).
Un altro aspetto fondamentale che riguarda il medico è la
firma digitale. Una volta scritto il referto il medico deve,
tramite certificato digitale firmare il referto in modo da
garantire a tutti gli operatori del sistema la propria identità
e veriticità. Ciò se basta a confermare chi ha redatto il
referto non da certezze su quando il referto sia stato fatto e
firmato; quindi una volta scritto, il referto firmato deve
essere spedito ad un web service esterno chiamato Time
Stamp Service
il quale sancirà in modo inequivocabile l’
istante temporale in cui il dottore ha sottomesso il referto al
sistema.
Il web service Time Stamp rimanderà al medico il referto
con il Time Stamp e il medico lo spedirà al repository
centrale che lo immagazzinerà.
Fig. 2.7 – Flusso di operazioni.
- 24 -
CAP. 2 – PROGETTO MIRO
In questo modo si offrono le garanzie necessarie sulla
fase di refertazione.
Fig. 2.8 – Fase di Refertazione.
- 25 -
CAP. 2 – PROGETTO MIRO
2.3 SOLUZIONI TECNICHE
MiRo è un applicazione “object-oriented” basata su
internet che fa uso di database relazionali per memorizzare
i dati. Questa applicazione, basata su un modello client
server
viene eseguita all’interno di un web browser
standard utilizzando la Java Virtual Machine, riducendo in
maniera significativa i tempi e le difficoltà di configurazione
dei client. Questo è un requisito fondamentale specialmente
in ambiente remoto.
MiRo è un sistema che si basa su di un’architettura
orientata ai servizi, implementata attraverso Web Services,
i quali stanno diventando uno standard “de facto” per
quanto riguarda la distribuzione di servizi all’interno di un
ambiente
eterogeneo
offrono un insieme
come Internet.
I
Web
Services
di standard di comunicazione che
permettono a diverse applicazioni di scambiarsi dati e
servizi
applicativi.
Tutto
ciò
garantisce
la
massima
accessibilità da parte degli operatori.
L’architettura prescelta e’ quella delineata da Java 2
Standard Edition di Sun e gli strumenti di sviluppo sono:
• Eclipse 3.1 – come piattaforma di sviluppo
• Apache Axis e Java Servlet – per la realizzazione
dei web service
• Apache Struts e Java Sever Pages – per le
interfacce web
- 26 -
CAP. 2 – PROGETTO MIRO
Data la sua architettura così generica il sistema può
operare su qualsiasi piattaforma che supporti i web services
realizzati in Java. I database supportati sono tutti quelli con
interfacce JDBC (nel nostro caso MySQL).
I client possono accedere in qualsiasi momento per
consultazione o inserimento dati utilizzando un comune
Web Browser. Ogni operatore accederà a funzionalità
diverse
del
sistema
sulla
base
del
proprio
profilo
professionale.
2.3.1 COMUNICAZIONE SICURA
Un aspetto al quanto fondamentale che è stato oggetto
di
studio
e
di
progettazione
nel
nostro
lavoro,
è
rappresentato dalla comunicazione sicura e dal mutuo
riconoscimento. Anche se, come detto precedentemente, in
questo lavoro non vengono mai trattati i dati sensibili
relativi ai pazienti (ossia le informazioni personali), la
sicurezza delle comunicazioni all’ interno del sistema svolge
un ruolo fondamentale, perché la struttura è stata pensata
e sviluppata per applicazioni che si basano su Internet, rete
insicura per sua natura, si è reso necessario utilizzare il
protocollo
di
comunicazione
https
che
rappresenta
l’
equivalente del classico http, dove le informazioni viaggiano
in maniera criptata; le transazioni effettuate vengono
- 27 -
CAP. 2 – PROGETTO MIRO
criptate
tramite
lo
standard
SSL
con
mutuo
riconoscimento.
Alla base di una comunicazione sicura, è necessario un
riconoscimento
di
entrambi
conversazione.
Tutto
ciò
è
i
stato
partecipanti
possibile
alla
attraverso
l’utilizzo di certificati digitali, che garantiscano l’ identità di
chi si collega al sistema.
Il certificato digitale rappresenta una sorta di carta
identità elettronica per chi si aggancia al sistema.
Tramite l’utilizzo della tecnologia SSL e dei certificati
vengono soddisfatti i quattro requisiti fondamentali per la
sicurezza:
• Autenticazione: garanzia che l’utente sia chi
dichiara di essere. Ottenuta grazie al certificato
ed agli Username e Password.
• Confidenzialità:
essere
letti
garanzia
che
i
esclusivamente
dati
possono
dall’utente
autorizzato. Ottenuta grazie ai certificati.
• Integrità:
vengano
garanzia
modificate
che
le
informazioni
durante
la
non
trasmissione.
Ottenuta grazie alla crittografia.
• Non-ripudiazione: garanzia che chi utilizza il
programma tramite il certificato se ne assuma le
responsabilità.
- 28 -
CAP. 2 – PROGETTO MIRO
2.3.2 Messaggi SOAP
La comunicazione all’ interno del sistema, avviene con
scambio di messaggi SOAP.
I dati si inviano come allegati ai messaggi SOAP,
abbiamo
scelto
questa
tecnica
per
lo
scambio
di
informazione perché avendo come obbiettivo quello di
creare una struttura in grado di adattarsi a qualsiasi tipo di
esame, era importante avere la possibilità di scambiare
messaggi di dimensioni variabili, in questo modo abbiamo
raggiunto tale obbiettivo.
Ad esempio, un dato proveniente da un laboratorio
radiologico produce dei file Dicom di dimensioni che si
aggirano attorno ai 40 Mb (dipende dall’ esame), con
questo
sistema
non
si
sono
verificati
problemi
di
trasmissione dei pacchetti.
Una cosa importante da notare è che per implementare
questa struttura si ha bisogno di una rete a larga banda che
consenta le transizioni di file di dimensione variabile.
- 29 -
CAP. 3 – MUTUO RICONOSCIMENTO E INTERFACCE GRAFICHE
CAPITOLO 3
MUTUO RICONOSCIMENTO E
INTERFACCE GRAFICHE
Analisi degli attori principali dell’architettura, dal
laboratorio al medico.
3.1 Laboratorio
3.1.1 Web Service laboratorio
3.1.2 Mutuo Riconoscimento
3.1.3 Interfacce grafiche
3.2Medico
3.2.1 Mutuo Riconoscimento
3.2.2 Interfacce grafiche
3.2.3 Firma del referto
- 30 -
CAP. 3 – MUTUO RICONOSCIMENTO E INTERFACCE GRAFICHE
3.1 LABORATORIO
Il laboratorio come visto in precedenza rappresenta uno
degli attori fondamentali del nostro sistema. E’ qui che
viene effettuato l’esame e dove viene memorizzato il dato
digitale, ed è qui che si chiude l’intero arco del processo
dove termina la fase di refertazione.
3.1.1 Web Service Laboratorio
Fig. 3.1 – Struttura del Web Service Laboratory
Anche il laboratorio ha bisogno di un web service che
mette a disposizione una serie di metodi (quelli in colore
giallo) per lo scambio dei messaggi con il repository
centrale.
- 31 -
CAP. 3 – MUTUO RICONOSCIMENTO E INTERFACCE GRAFICHE
3.1.2 Mutuo Riconoscimento
Una volta effettuato l’accesso tramite un semplice web
browser( ad esempio internet explorer) il sistema tramite
l’utilizzo dei certificati digitali effettua il riconoscimento del
laboratorio che ha compiuto l’accesso. Ciò avviene tramite l’
estrapolazione del common name dal certificato il quale
viene confrontato con il dato presente nella
tabella
tm_utenti nel campo utn_cn, se il confronto ha esito
positivo il sistema effettuerà un accesso guidato all’ interno
del repository, visualizzando tramite opportune interfacce
solo i dati relativi agli eventi ad esso connessi.
3.1.3 Interfacce grafiche
Il sistema offre al client del laboratorio dell’ interfacce
user-friendly di facile utilizzo.
Le varie form sono state create tramite tecnologia jsp
con l’ausilio del tool struts (entrambi questi prodotti
verranno spiegati successivamente).
L’interfaccia per l’inserimento dei dati da parte del
laboratorio nel repository è la seguente:
- 32 -
CAP. 3 – MUTUO RICONOSCIMENTO E INTERFACCE GRAFICHE
Fig. 3.2 – Form di visualizzazione degli eventi
Lo sfondo blu denota il laboratorio, nella seguente form
al client viene proposta una tabella che contiene le
informazioni sullo stato degli esami presenti nel repository
riferiti a quel particolare laboratorio, i campi visualizzati
sono:
• Data: “ora e data di emissione del dato nel
repository”
• Utente: “struttura che ha generato l’evento”
• Codice: “codice identificativo dell’esame effettuato”
• Tariffa: “tipo do esame effettuato”
• Stato: “stato dell’esame aperto,chiuso o refertato”
• Link: “possibilità di effettuare il download
dell’esame”
- 33 -
CAP. 3 – MUTUO RICONOSCIMENTO E INTERFACCE GRAFICHE
E’ importante notare che il laboratorio cliccando sul link
dello stato può decidere se chiudere il referto o no.
Scegliendo l’opzione open dal menù si apre la seguente
form:
Fig. 3.3 – Form per l’inserimento dei dati
In questa form viene offerta al client la possibilità di
aprire un evento ossia di generare nel web service
repository una riga editando i seguenti campi:
• Codice Tariffa: “codice identificativo dell’esame
effettuato”
• File dell’esame: “si allega il dato digitale prodotto in
laboratorio”
• Unità esterna: “si indica se è interno o esterno alla
struttura attinente”
- 34 -
CAP. 3 – MUTUO RICONOSCIMENTO E INTERFACCE GRAFICHE
• Richiedente: “si indica chi ha richiesto l’esame”
• Impegnativa: “si mette un codice alfa numerico per
l’impegnativa”
• Note: “campo per editare delle note in merito
all’esame”
- 35 -
CAP. 3 – MUTUO RICONOSCIMENTO E INTERFACCE GRAFICHE
3.2 MEDICO
Il medico è l’ultima figura che prendiamo in esame. E’
qui che viene effettuato il referto ed è qui che si viene a
creare il processo di second opinion.
3.2.1 Mutuo Riconoscimento
Come avviene per il laboratorio anche il medico può
accedere al sistema con l’utilizzo di un semplice web
browser (ad esempio internet explorer) collegandosi al sito
del web service repository.
Al momento dell’accesso, il sistema tramite l’utilizzo dei
certificati digitali effettua un muto riconoscimento per il
medico e per il web service repository. Il riconoscimento del
dottore avviene tramite il common name del proprio
certificato digitale (presente nella propria smart card), il
quale viene confrontato con il con il dato presente nella
tabella tm_utenti (del repository) nel campo utn_cn, se il
confronto ha esito positivo il sistema effettuerà un accesso
guidato all’ interno del repository, visualizzando tramite
opportune interfacce solo i dati relativi agli eventi che esso
è in grado di rifertare.
- 36 -
CAP. 3 – MUTUO RICONOSCIMENTO E INTERFACCE GRAFICHE
In questo modo è garantita l’ affidabilità del sistema da
un punto di vista puramente medico.
3.3.2 Interfacce grafiche
Nel
progettare
l’interfaccia
utente,
come
per
il
laboratorio, lo scopo era creare delle form di tipo userfriendly in modo da facilitare il loro impiego da parte del
personale medico.
Appena effettuato l’accesso e superata la fase di mutuo
riconoscimento, al client, viene presentata la seguente
form:
Fig. 3.4 – Form di visualizzazione eventi
Si può notare, lo sfondo verde associato al dottore
viceversa quello del laboratorio erà blu. Si vede subito che
- 37 -
CAP. 3 – MUTUO RICONOSCIMENTO E INTERFACCE GRAFICHE
l’unica cosa che cambia nella struttura è il menù dove è
assente l’opzione open perché quella erà caratteristica del
laboratorio l’unico in grado di generare un evento.
Il dottore scegliendo l’esame può decidere di scaricare il
dato digitale nella propria postazione, premendo download,
e quindi visualizzarlo; fatto ciò tramite il link stato si aprirà
una nuova form :
Fig. 3.5 – Form per effettuare il referto.
In questa finestra vengono visualizzati anche i referti
precedentemente effettuati da altri medici, se lo stato
dell’evento era impostato su aperto o refertato il dottore
nell’apposita casella di testo potrà editare il suo referto
avvalendosi della possibilità di confrontarsi con i pareri
medici precedentemente inseriti. In questo modo si crea ciò
che oggigiorno si definisce meccanismo di “second opinion”.
Scritto l’esame il medico aggiungerà alla lista degli altri
- 38 -
CAP. 3 – MUTUO RICONOSCIMENTO E INTERFACCE GRAFICHE
referti il proprio premendo il tasto confirm. E’ qui che si
mette in modo il meccanismo di firma digitale.
3.2.2 Firma del referto
Fig. 3.6 – Funzione di Hash.
Il processo di firma digitale viene effettuato grazie ad
una libreria sviluppata da un nostro collega, che si occupa
della cifratura di dati binari utilizzando i certificati digitali
che risiedono all’interno di una smart-card. L’interfaccia di
questa libreria principalmente espone due metodi: uno per
firmare il dato e uno per verificarne l’integrità.
La
firma
digitale
di
un
documento
è
il
risultato
dell'applicazione di una funzione hash al documento stesso.
Per essere utile, però, la funzione hash deve soddisfare a
due importanti proprietà. Primo, dev'essere difficile trovare
due documenti che possiedono la stessa valore di hash;
- 39 -
CAP. 3 – MUTUO RICONOSCIMENTO E INTERFACCE GRAFICHE
secondo, dato un valore di hash deve essere difficile
recuperare il documento che ha prodotto quel valore.
Il referto per mezzo di una funzione di hash viene
convertito in una sequenza di byte di lunghezza finita, nela
caso dell’algoritmo SHA-1 l’array è di 20 byte. Una funzione
hash è una funzione da molti a uno che mappa i suoi valori
di ingresso in un valore appartenente ad un insieme finito.
Tipicamente questo insieme è un intervallo di numeri
naturali. Nel nostro caso un flusso di byte di lunghezza
variabile, il nostro referto, viene trasformato in una
sequenza di lunghezza finita, chiamata digest. È questo
nuovo oggetto binario che viene inviato alla procedura di
firma digitale che a questo punto utilizzando il digest del
referto come input di un’ulteriore funzione di hash eseguita
dalla smart-card che cripta i dati utilizzando il certificato
digitale. Questo processo è stato realizzato in maniera
esterna al nostro sistema, in modo da non soffrire dei
problemi di implementazione dovuto alle differenze tra le
varie smart-card, inoltre è possibile affinare la tecnica di
firma aggiungendo la chiamata ad un servizio di timestamping che possa garantire l’istante di tempo in cui il
dato è stato firmato.
Un'altra persona può controllare la firma applicando la
stessa funzione di hash alla propria copia del documento e
confrontando il valore di hash ottenuto con quello del
documento
originale.
Se
coincidono,
può
praticamente certo che i documenti siano identici.
- 40 -
essere
CAP. 3 – MUTUO RICONOSCIMENTO E INTERFACCE GRAFICHE
Fig. 3.7 – Generazione e verifica della firma digitale.
La verifica della firma viene eseguita dal repository per
garantire all’utente che visualizza i referti l’identità della
persona che ha scritto il documento. Nel nostro sistema
viene richiamata una funzione di libreria che partendo dal
documento originale effettua di nuovo il processo che
confronta il documento firmato.
- 41 -
CAP. 4 - TECNOLOGIE SOFTWARE
CAPITOLO 4
TECNOLOGIE SOFTWARE
Panoramica delle tecnologie software impiegate
nella realizzazione del progetto dal lato client con
delle web application.
4.1 Java Platform
4.1.1 Java Server Pages
4.2 Apache Tomcat
4.2.1 Comunicazione SSL
4.3 Strumenti di Sviluppo
4.3.1 Apache Struts
- 42 -
CAP. 4 - TECNOLOGIE SOFTWARE
4.1 JAVA PLATFORM
Java
appena
è
uscito
è
stato
accolto
con
molto
entusiasmo dalla comunità mondiale dei progettisti di
software e dei provider di servizi Internet, questo perché
Java
permetteva
agli
utenti
di
Internet
di
utilizzare
applicazioni sicure e indipendenti dalla piattaforma, che si
possono trovare in qualsiasi punto della rete.
Java è quindi nato come linguaggio per la rete, per
affiancare l'Hyper Text Markup Language (HTML), il quale
non è un linguaggio di programmazione vero e proprio, e
per dargli quella sicurezza che l'HTML non ha. Da quando è
nato Java sulla rete si è iniziato a poter parlare di numeri di
carte di credito e di informazioni sicure, notizia che ha
molto affascinato le grosse società mondiali, le quali hanno
trasformato la vecchia Internet, rete ad appannaggio delle
sole università e centri di ricerca, nell'attuale mezzo di
comunicazione aperto a tutti.
Il linguaggio di programmazione Java è stato creato
verso la metà degli anni novanta, è il più recente tra i suoi
cugini, e per questo è ancora in fase evolutiva, tanto che
ogni anno circa ne viene rilasciata una nuova relase.
Da linguaggio nato solo per la rete è divenuto un vero e
proprio linguaggio di programmazione, paragonabile, dal
punto di vista delle funzionalità, al più blasonato C++. Java
e la maggior parte degli altri linguaggi possono essere
- 43 -
CAP. 4 - TECNOLOGIE SOFTWARE
paragonati solo dal punto di vista delle funzionalità, perché
sono fondamentalmente molto diversi, infatti Java compila i
sorgenti dei suoi programmi in un codice detto Bytecode,
diverso dal linguaggio della macchina su cui è compilato,
mentre linguaggi come il C++ compilano i sorgenti dei
programmi in un codice che è il codice della macchina ( per
macchina intendo computer + sistema operativo ) su cui è
eseguito. Quindi per eseguire un programma Java occorre
avere uno strumento che è chiamato Java Virtual Machine,
la quale interpreta il bytecode generato dal compilatore
Java e lo esegue sulla macchina su cui è installato. Grazie
alla
Java
Virtual
Machine
Java
è
indipendente
dalla
piattaforma, infatti il programma compilato Java è legato
alla JVM e non al sistema operativo, sarà quindi possibile
eseguire lo stesso programma Java, compilato una sola
volta su una qualche macchina con un compilatore Java
versione
X,
su
una
piattaforma
Windows
e
su
una
piattaforma Linux, per fare questo però c'è bisogno che sia
Windows che Linux abbiano installato una Java Virtual
Machine che supporti la versione X di Java. Le due JVM
installate sulle due piattaforme diverse sono lo stesso
programma compilato una volta per Windows ed una volta
per Linux, come avveniva con i programmi scritti in
linguaggi come il C/C++.
Una Java Virtual Machine è implementata anche nei vari
Browser (Come Netscape e Explorer) per poter eseguire i
programmi Java incontrati nella rete, i cosidetti Applet.
- 44 -
CAP. 4 - TECNOLOGIE SOFTWARE
Questo però, unito al fatto che Java ancora si evolve, causa
degli ovvi problemi di incompatibilità: capita sempre che il
più moderno Browser supporti una versione precedente di
Java
rispetto
all'ultima
versione
rilasciata
dalla
Sun
Microsystem, inoltre bisogna tener presente che non tutti
gli utenti di Internet navigano usando l'ultima versione di
Netscape o di Explorer. Quindi volendo creare un applet ed
inserirlo in un nostro documento HTML, dobbiamo tenere
presente
questi
problemi,
e
cercare
di
scrivere
un
programma che sia compatibile con la maggior parte delle
JVM inplementate nei vari browser.
Un altro problema da affrontare è quello della scelta del
compilatore Java da utilizzare, infatti esistono vari ambienti
integrati per editare, compilare, debuggare ed eseguire
programmi Java, come quelli della Borland, della Microsoft,
della Symantec. Tutti questi ambienti offrono dei tool di
sviluppo
eccellenti,
come
editori
grafici
di
finestre,
debugger molto interessanti, però hanno due problemi, il
primo è che si pagano, anche molto, il secondo è sempre lo
stesso della compatibilità, infatti essi spesso si trovano
indietro alla relase della sun, ed inoltre aggiungono delle
classi che poi le JVM implementate nei browser non hanno.
Il mio consiglio è quello di usare le JDK ( Java
Development Kit ) della Sun, le quali comprendono sia il
compilatore che la Java Virtual Machine per eseguire i
programmi da noi compilati, inoltre sono freeware (non
costano niente) e sono scaricabili dalla rete ed i browser si
- 45 -
CAP. 4 - TECNOLOGIE SOFTWARE
adeguano pian piano a questa versione di Java. Se volete
scrivere applet per i vecchi browser dovete scaricarvi la
versione 1.2.1 di Java, però questa versione è niente alla
versione attualmente più gettonata, ovvero alla 1.5.1.
Un ultimo problema che ha Java è la lentezza, infatti, come
già detto, esso è interpretato, quindi le istruzioni Java
prima
di
essere
eseguite
dalla
macchina
vengono
interpretate dalla JVM, ovvero per eseguire ogni istruzione
il computer eseguirà un numero di istruzioni macchina che
è più del doppio delle istruzioni che eseguirebbe se la
stessa istruzione fosse stata scritta in C, quindi avrete
bisogno di computer veloci per eseguire bene programmi
Java, e di questo vi sarete sicuramente accorti anche
navigando sulla rete. Anche la memoria è importante, si
compila e si esegue anche con soli 128Mb di RAM, ma per
fare le cose velocemente ne occorrono almeno 512. Per
finire
ritorno
al
Java
Development
Kit
della
Sun
Microsystem, con questo è possibile produrre tutto il
software che si vuole senza dover pagare diritti di uso del
prodotto come avviene con il Borland Jbuilder, il Symantec
Cafe, e il Microsoft Visual Java.La principale differenza tra
Java e gli altri linguaggi di programmazione ad oggetti è
che
mentre
con
questi
ultimi
è
possibile
anche
porgrammare ad oggetti con Java si deve assolutamente
programmare ad oggetti.
- 46 -
CAP. 4 - TECNOLOGIE SOFTWARE
4.1.1 Java Server Pages
JSP (Java Server Pages) è una tecnologia semplice ma
potente, che permette di creare Pagine HTML dinamiche
lato server. In questo stralcio presentiamo, aiutandoci con
esempi, le caratteristiche principali.
Introduzione
JSP (Java Server Pages) è una tecnologia semplice ma
potente, che permette di creare Pagine HTML dinamiche
lato server. Questa tecnologia agli occhi del programmatore
viene gestita per mezzo di un linguaggio di script che è in
grado di mescolare codice HTML, componenti riusabili
(JavaBeans), applicazioni remote (Servlet), codice Java e
script Java-like. Le Pagine JSP sono un'estensione diretta
dei
Servlet
Java
e
offrono,
rispetto
ad
altre
attuali
tecnologie Server-Side, il vantaggio e la possibilità di
separare la sezione di gestione delle operazioni e di
produzione dei contenuti, da quello di visualizzazione vera e
propria. Normalmente una Pagina JSP è composta da:
porzioni di codice HTML, JavaScript, CSS e così via, non
compilati dal motore Jsp (Jsp Engine) e comunemente
definiti blocchi di codice statico;
porzioni di codice Java, compilati dal motore Jsp, che
prendono il nome di blocchi di codice dinamico.
Come lavorano le Pagine JSP
- 47 -
CAP. 4 - TECNOLOGIE SOFTWARE
La prima volta che un Client (di norma un generico
browser) effettua la richiesta di una Pagina JSP ad un Web
Server (container JSP), questo la compila creando un
oggetto Servlet che risiederà in memoria; solo dopo questo
passaggio
l'output
viene
inviato
al
Client
che
potrà
interpretarlo come se fosse una semplice Pagina HTML. Ad
ogni richiesta successiva della medesima Pagina JSP, il Web
Server controlla se è stata modificata: in caso negativo
richiama il Servlet già compilato, altrimenti si occupa di
eseguire nuovamente la compilazione e memorizzazione del
nuovo Servlet. Conseguenza di questo meccanismo è che la
prima volta che si invoca una Pagina JSP il sistema sarà un
pò
più
lento
del
normale,
mentre
dalle
invocazioni
successive si avranno prestazioni di tutto rispetto. Un
semplice esempio del codice di una Pagina JSP e dell'output
prodotto sono riportati qui di seguito:
<%@page language="java"%>
<%@page import="java.util.*"%>
<html>
<head>
<title>Java Server Pages: Hello World</title>
</head>
<body>
<% out.println(" Hello World JSP! "); %>
<%= new Date() %>
</body>
- 48 -
CAP. 4 - TECNOLOGIE SOFTWARE
</html>
Se
ci
si
sofferma
esclusivamente
sulla
forma
del
documento JSP è possibile notare che l'aspetto di codice
JSP ricalca quello di una Pagina HTML e non quello di una
classe Java. Analizzando successivamente il codice del
Servlet generato dal Web Server alla prima invocazione
della Pagina JSP, che può variare leggermente in base al
motore Jsp utilizzato, si nota che il metodo che effettua il
servizio vero e proprio è _jspService() (Per visualizzare il
codice
Servlet
clicca
qui).
All'interno
del
metodo
_jspService() troviamo, oltre ad una serie di variabili e
controlli fondamentali per il funzionamento del Servlet, la
traduzione dei tag HTML contenuti nella Pagina JSP in
codice Java.
Componenti di un Pagina JSP
Una Pagina JSP può essere composta da:
direttive;
script JSP;
oggetti impliciti;
azioni.
Direttive
Le
direttive
sono
elementi
JSP
che
forniscono
informazioni globali su un'intera Pagina JSP. Un esempio
potrebbe essere una direttiva che indichi il linguaggio da
utilizzare nella compilazione della Pagina JSP. La sintassi
- 49 -
CAP. 4 - TECNOLOGIE SOFTWARE
delle
direttive
è
la
seguente
<%@
direttiva
{attributo="valore"}%> . Volendo indicare al motore Jsp
che il linguaggio da utilizzare nelle Pagine JSP deve essere
il Java, è possibile utilizzare la riga di codice seguente:
<%@
page
language="java"%>.
Attualmente
nella
specifica JSP sono definite tre direttive: page, include,
taglib.
• Direttiva Page definisce informazioni globali riguardanti
l'intera Pagina JSP che la contiene. Le impostazioni che
modifica influenzano direttamente la compilazione della
pagina.
• Direttiva Include serve per inserire testo e codice
all'interno di una Pagina JSP al momento della sua
traduzione. La sua sintassi è la sequente: <%@include
file="specificoURL"%>.
• Direttiva
Taglib
personalizzato
permette
di
tag
di
creare
chiamato
tag
un
library.
insieme
Questa
direttiva dichiara che la pagina intende utilizzare tag
personalizzati, indica univocamente la libreria che li
definisce e associa loro un prefisso che li distingue da
quelli presenti in altre librerie. La sintassi della direttiva
taglib
è
la
seguente:
uri="URIdellaLibreriadiTag"
<%@taglib
prefix="prefissoTAG"%>
dove :
uri
identifica
univocamente
personalizzati;
- 50 -
un
insieme
di
tag
CAP. 4 - TECNOLOGIE SOFTWARE
prefix definisce una stringa utilizzata per distinguere una
tag personalizzato da uno invece standard.
Script JSP
Gli script JSP consentono di includere porzioni di codice
direttamente all'interno di Pagine HTML, esistono tre
elementi coinvolti negli script JSP, ciascuno dei quali ha una
posizione ben definita all'interno del Servlet generato:
Dichiarazioni, Espressioni e Scriptlet.
• Dichiarazioni JSP servono per dichiarare variabili e
metodi del linguaggio di script usato nelle Pagine JSP. La
sintassi delle dichiarazioni JSP è la seguente: <%!
Dichiarazione %>, un esempio <%! String nome=new
String("Andrea"); %> nel caso in cui si voglia dichiarare
una variabile di tipo String contenente un valore iniziale
diverso da null; <%! public String getName() { return
name; } %> nel caso in cui si voglia definire un metodo
che ritorni una variabile, definita in questo caso nella
dichiarazione precedente, di tipo String.
• Espressioni JSP sono degli elementi del linguaggio di
script che vengono valutati logicamente, letteralmente o
matematicamente, il cui risultato viene convertito in una
java.lang.String. Le espressioni sono valutate all'atto
della richiesta HTTP. La stringa risultante viene inserita al
posto dell'espressione nel file .jsp, nel caso l'espressione
non può essere convertita, si verifica un errore di
- 51 -
CAP. 4 - TECNOLOGIE SOFTWARE
traduzione. La sintassi di un'espressione JSP è la
seguente: <%= Espressione %>, un esempio Ciao <%=
getName() %>.
• Scriptlet
JSP
possono
contenere
qualsiasi
tipo
di
istruzione a patto che siano valide per il linguaggio
specificato nella direttiva language. Vengono eseguiti al
momento
della
richiesta
e
possono
far
uso
di
dichiarazioni, espressioni e JavaBeans. La sintassi degli
scriptlet JSP è la seguente: <% Sorgente dello Scriptlet
%>. Importante sottolineare che il codice contenuto tra i
tag <% %> viene inserito nel metodo _jspService() del
Servlet al momento della compilazione (Clicca qui per
visualizzare un esempio di codice Servlet).
Oggetti Impliciti
Scrivendo Pagine JSP si ha l'accesso ad alcuni oggetti
impliciti appositamente creati per essere utilizzati nei
documenti
JSP
senza
dover
essere
dichiarati
anticipatamente. Gli oggetti impliciti più importanti sono:
request, response, pageContext, session, application, out,
config, page.
• request permette il recupero dell'informazioni legate alla
richiesta commissionata dal browser dell'utente come i
parametri, le intestazioni, i cookie e così via.
• response permette l'accesso al canale di output, per la
generazione della risposta HTTP; è possibile comunicare
- 52 -
CAP. 4 - TECNOLOGIE SOFTWARE
un errore, inviare una particolare intestazione, settare un
cookie e altro.
• pageContext è molto generico e rappresenta qualsiasi
cosa abbia a che fare con il contesto di esecuzione della
pagina; da esso è possibile ricavare gli altri oggetti
impliciti.
• session permette di associare all'utente che richiede la
pagina
un'informazione
recuperabile
in
ogni
altro
documento dell'applicazione. E' possibile memorizzare le
scelte effettuate dall'utente in una o più variabili di
sessione così da poterne tener traccia.
• application fornisce un accesso al contesto di esecuzione
dell'applicazione Web, cioè offre la possibilità di ottenere
informazioni sul Servlet Engine che esegue l'applicazione,
recuperare i parametri di inizializzazione del software,
registrare
dei
messaggi
accessibili
da
ogni
pagina
appartenente al contesto.
• L'oggetto out è di tipo JspWriter; ad esso corrisponde il
canale di output instaurato con il browser dell'utente che
ha richiesto la pagina.
• config non è utilizzato frequentemente dagli sviluppatori
poichè il container imposta o rileva automaticamente le
informazioni accessibili tramite questo riferimento.
• page rappresenta la
parola chiave this dell'istanza
corrente della Pagina JSP.
- 53 -
CAP. 4 - TECNOLOGIE SOFTWARE
Azioni
Le azioni rappresentano un livello di astrazione che può
essere
utilizzato
per
incapsulare
agevolmente
compiti
comuni. Generalmente vengono impiegate per la creazione
o la manipolazione di oggetti, perlopiù JavaBeans. Alcune
azioni standard sono:
<jsp:useBean>: associa un'istanza di un JavaBean a un
ambito e ad un ID tramite una variabile di script dichiarata
con lo stesso nome; se non trova un'istanza "in vita" cerca
di crearla. Gli attributi più importanti legati a questa azione
sono:
id
:
rappresenta
l'identità
dell'istanza
dell'oggetto
all'interno dell'ambito specificato;
scope : rappresenta l'ambito dell'oggetto. Possibili scope:
page, request, session, application;
class : rappresenta il nome di classe che definisce
l'implementazione dell'oggetto.
Da
questa
azione
principale
derivano
le
seguenti
sottoazioni:
<jsp:setProperty>: imposta il valore di una proprietà di
un bean;
<jsp:getProperty>: prende il valore della proprietà del
bean referenziato, lo converte in un java.lang.String e lo
inserisce nell'oggetto out implicito;
Un JavaBeans è un componente Java al 100% che opera
all'interno di una qualsiasi macchina virtuale; è una classe
- 54 -
CAP. 4 - TECNOLOGIE SOFTWARE
Java che implementa l'interfaccia java.io.Serializable e
utilizza metodi pubblici get/set per esporre le proprietà.
<jsp:include>: fornisce un modo per includere risorse
aggiuntive, di tipo statico o dinamico, nella Pagina JSP
corrente. Gli attributi più importanti legati a questa azione
sono:
page : rappresenta la URL relativa della risorsa da
includere;
flush : questo attributo contiene un valore boolean che
indica se il buffer debba o meno essere svuotato.
<jsp:forward>: consente al motore Jsp l'inoltro, all'atto
dell'esecuzione, della risorsa corrente a una risorsa statica,
a un Servlet o ad una Pagina JSP. L'unico attributo possibile
per questa azione è:
page
:
rappresenta
la
URL
relativa
all'oggetto
da
inoltrare.
<jsp:param>: viene impiegata per fornire informazioni a
coppie di tag/valore, includendoli come sottoattributi delle
azioni
<jsp:forward>,
<jsp:useBean>,
<jsp:include>
all'atto dell'esecuzione, della risorsa corrente a una risorsa
statica, a un Servlet o ad una Pagina JSP. L'unico attributo
è:
name : rappresenta il nome del parametro referenziato;
value : rappresenta il valore del parametro referenziato.
Conclusioni
Quelle esposte, anche se in estrema sintesi, sono le
caratteristiche più salienti della tecnologia JSP che offre,
- 55 -
CAP. 4 - TECNOLOGIE SOFTWARE
rispetto ad altre attuali tecnologie Server-Side, la possibilità
ed il grosso vantaggio di separare le logiche di business
dalla loro presentazione.
- 56 -
CAP. 4 - TECNOLOGIE SOFTWARE
4.2 APACHE TOMCAT
Struttura di una applicazione web
La nozione di applicazione web è stata formalizzata per la
prima volta nella versione 2.2 delle specifiche delle servlet
Java. Sebbene il concetto di applicazione web sia piuttosto
ampio e dipendente dal contesto in cui viene esaminato, la
definizione
fornita
nelle
suddette
specifiche
risulta
di
portata sufficientemente generale.
Dal punto di vista dello sviluppatore di applicazioni web
basate
su
Java
risulta
particolarmente
importante
la
standardizzazione della struttura di tali applicazioni e
l'introduzione degli archivi WAR come strumento per il
deployment delle applicazioni web.
Struttura di una applicazione web
Una applicazione web è una gerarchia di file e directory
disposti secondo uno schema standard.
/webapp. Una applicazione web ha una propria directory
radice (root). Il nome della cartella corrisponde a ciò che
nella terminologia delle servlet viene chiamato context path
(nel seguito supporremo che tale nome di tale cartella sia
- 57 -
CAP. 4 - TECNOLOGIE SOFTWARE
webapp). La directory radice contiene tutti gli altri elementi
che compongono l'applicazione web.
File HTML, JSP, ...
La directory /webapp contiene i
documenti HTML, le pagine JSP, le immagini e le altre
risorse
che
compongono
l'applicazione
web.
Tali
file
possono essere strutturati in directory esattamente come si
farebbe per un sito web statico.
/webapp/WEB-INF. All'interno della cartella root si trova
una directory speciale, denominata WEB-INF. La funzione di
questa cartella è quella di contenere file riservati, come ad
esempio il file di configurazione dell'applicazione, web.xml.
Per questo motivo le specifiche impongono che la cartella
ed il suo contenuto debbano risultare inaccessibili per gli
utenti dell'applicazione.
/webapp/WEB-INF/web.xml.
Il
file
web.xml
viene
comunemente denominato deployment descriptor. Si tratta
del file di configurazione dell'applicazione web; in esso, ad
esempio, si definiscono gli alias delle servlet, i parametri di
inizializzazione, le mappature dei percorsi e così via.
/webapp/WEB-INF/classes
e
/webapp/WEB-INF/lib.
Queste due directory sono destinate a contenere le classi e
gli archivi Jar di cui la nostra applicazione web necessita. Se
dobbiamo utilizzare delle classi Java compilate (file con
- 58 -
CAP. 4 - TECNOLOGIE SOFTWARE
estensione
.class
andremo
a
copiarle
all'interno
di
/webapp/WEB-INF/classes, secondo l'usuale struttura di
directory Java (così se abbiamo una classe MiaServlet
contenuta nel package sito.servlet. il percorso del file
compilato
sarà
/webapp/WEB-
INF/classes/sito/servlet/MiaServlet.class).
Se
dobbiamo
utilizzare classi contenute in archivi Jar, invece, sarà
sufficiente copiarli in /webapp/WEB-INF/lib.
Archivi WAR
Una volta sviluppata una applicazione web possiamo
"impacchettarla" in un archivio WAR (Web Application
Archive). Un archivio WAR non è altro che un archivio Jar,
una vecchia conoscenza dei programmatori Java, la cui
estensione viene modificata in .war semplicemente per
indicare che il contenuto dell'archivio è una applicazione
web.
Gli archivi WAR hanno una duplice funzione: oltre a
quella ovvia di comprimere tutte le componenti di una
applicazione in un unico archivio, costituiscono il formato di
deployment dell'applicazione stessa. Il termine inglese
deployment indica la messa in opera dell'applicazione.
Uno scenario tipico è quello in cui l'applicazione viene
sviluppata
localmente
per
poi
essere
trasferita,
ad
ultimazione, sul server vero e proprio (detto anche di
- 59 -
CAP. 4 - TECNOLOGIE SOFTWARE
produzione). In questo caso è sufficiente creare il file WAR,
copiarlo sul server di produzione e seguire le istruzioni per
l'installazione del WAR relative al servlet container che si
sta utilizzando. Nel caso di Tomcat, l'installazione di un
WAR è estremamente semplice: è sufficiente copiare il file
nella directory webapps e avviare (o riavviare) il server,
che provvederà da solo a decomprimere l'archivio e ad
avviare l'applicazione.
Un esempio di comando per la creazione di un archivio
WAR (da digitare dopo essersi spostati all'interno della
cartella webapp) è il seguente:
jar cvf webapp.war .
E' consigliabile, in ogni caso, fare riferimento alla
documentazione ufficiale del tool jar per una spiegazione
esaustiva delle opzioni disponibili.
In questa breve nota abbiamo preso dimestichezza con la
strutturazione di una applicazione web, così come definita
nelle specifiche Servlet a partire dalla versione 2.2.
Organizzando le nostre applicazioni in tal modo otterremo
diversi vantaggi:
• aumenteremo la portabilità dell'applicazione, rendendone
più semplice la messa in opera;
- 60 -
CAP. 4 - TECNOLOGIE SOFTWARE
• renderemo l'applicazione più comprensibile ad altre
persone, in quanto sarà molto più semplice sapere dove
si trovano le classi, gli archivi Jar e le altre componenti
dell'applicazione stessa;
• potremo racchiudere l'intera applicazione in un archivio
WAR, rendendone semplice l'installazione su tutti i
servlet container conformi alle specifiche Sun.
Abbiamo così compiuto il primo passo per la realizzazione
di una applicazione web in ambiente Java, che abbiamo
imparato a strutturare in modo standard. Il prossimo
argomento
da
affrontare
sarà
la
configurazione
dell'applicazione attraverso il già citato file web.xml.
L'ambiente di Tomcat
Tomcat contiene al suo interno tutte le funzionalità
tipiche di un web server, ovvero - in sintesi - ha la capacità
di interpretare una richiesta di una risorsa veicolata su
protocollo HTTP, indirizzarla ad un opportuno gestore (o
prenderla dal filesystem) e restituire poi il risultato (codice
HTML o contenuto multimediale che sia). In questo aspetto
non differisce molto da altri web server, come Apache, se
non che spesso si rivela meno prestante. La caratteristica
- 61 -
CAP. 4 - TECNOLOGIE SOFTWARE
innovativa di Tomcat non è quindi quella di essere un
veloce web server, ma piuttosto quella di fornire allo
sviluppatore un vero e proprio ambiente nel quale girano
applicazioni Java (le servlet). In questo stralcio cercheremo
di
comprendere
meglio
come
sia
strutturato
questo
ambiente Java nel quale prenderanno vita le nostre
applicazioni lato server.
Contenitori in Tomcat
Come
nelle
normali
applicazioni,
anche
nella
programmazione lato server gli oggetti creati devono avere
uno scopo, ovvero essere definiti ed accessibili in un
determinato
contesto.
suddividere
lo
spazio
Utilizzare
delle
Tomcat
risorse
equivale
in
a
contenitori
sostanzialmente indipendenti nei quali possono essere
depositati oggetti Java, secondo una logica orientata al
web. Per comprendere appieno questo concetto analizziamo
nel
dettaglio
i
singoli
contenitori
che
sono
tra
loro
strutturati in maniera abbastanza gerarchica.
Tomcat
Chiaramente il primo livello corrisponde al web server
stesso che avrà un insieme di variabili ad esso associate.
Ad esempio qui dentro vi sarà indicazione del numero di
thread attualmente in esecuzione, della versione di Tomcat
o altre proprietà globali generalmente di poco interesse
nella programmazione.
- 62 -
CAP. 4 - TECNOLOGIE SOFTWARE
Contesto
Quando un utente accede al web server accede in realtà
ad una sezione specifica del web server (a un certo dominio
virtuale
o
directory,
ad
esempio)
identificata
sostanzialmente dalla URL. Nel gergo di Tomcat la sezione
viene chiamata contesto (context). All'interno di questo
contenitore si troveranno quindi oggetti comuni a tutta la
sezione, che saranno gli stessi per tutti gli utenti e tutte le
applicazioni
generato
del
contesto.
all'avvio
indipendentemente
di
Questo
Tomcat
dal
fatto
contenitore
e
che
viene
rimane
qualcuno
attivo
lo
stia
interrogando in quel momento. Questo non vuol dire che
rimanga invariato, anzi, il suo contenuto cambierà in
funzione
delle
richieste
ricevute
ed
ogni
elemento
contribuirà a definire l'ambiente di tutta la sezione.
Sessione
Il
primo
contenitore
con
caratteristiche
fortemente
orientate al web è quello associato alla sessione (Session).
Come dice il nome questo contenitore viene associato ad un
utente (o, meglio, ad un client) per tutto il tempo per il
quale rimane connesso ad un contesto specifico. Al suo
interno
verranno
memorizzati
oggetti
che
saranno
accessibili solo a quell'utente e ne personalizzeranno
l'ambiente rispetto ad altri client che utilizzino risorse dello
stesso contesto nello stesso momento.
- 63 -
CAP. 4 - TECNOLOGIE SOFTWARE
Richiesta
Il contenitore con la vita più breve è la richiesta
(Request) che nasce e muore nell'ambito della singola
transazione web. Raramente questo contenitore viene
riempito
da
applicazioni
anche
se
svolge
un
ruolo
fondamentale nel flusso dei dati che attraversano Tomcat.
Il flusso di dati
Abbiamo
visto
che
l'oggetto
Context
viene
creato
all'avvio di Tomcat mentre l'oggetto Request nasce muore
ad ogni richiesta. Andiamo ad analizzare un po' più in
dettaglio il flusso logico che segue Tomcat nel processare le
singole richieste web che riceve.
Richiesta di una risorsa
Supponiamo che un client acceda a una risorsa su di un
server su cui gira Tomcat. Innanzi tutto viene instanziato
un oggetto Request, Req, in Tomcat nel quale vengono
inserite tutte le informazioni ricevute tramite HTTP (dalla
url richiesta sino ai cookies) e "al suo fianco" viene
instanziato un oggetto risposta (Response, Res) nel quale
costruire pian piano la risposta da restituire al client.
Leggendo la url all'interno della richiesta Tomcat è quindi in
grado di comprendere a quale dei contesti residenti in
memoria debbano essere consegnati questi due oggetti Req
e Res.
- 64 -
CAP. 4 - TECNOLOGIE SOFTWARE
Contesto e sessione
Il contesto invocato da Tomcat provvederà a vedere se
esiste già una sessione attiva per quel tipo di client
leggendone la "firma" nella richiesta (sotto forma di cookie
o nella url, a seconda del metodo usato). Se la sessione,
Ses, esiste già tra quelle immagazzinate nel context, il
contesto la riprende e la affianca agli oggetti Req e Res. A
questo punto l'ambiente è stato completamente definito e il
web
server
può
passare
il
controllo
all'applicazione
associata alla risorsa in questione.
Le Servlet
A questo punto del percorso logico, il contesto è in grado
di decidere (sulla base del suo file di configurazione) a
quale
applicazione
passare
il
controllo
all'interno
dell'ambiente di lavoro definito in tutto il percorso (la più
semplice delle applicazioni è chiaramente quella che si
occupa di restituire un file presente sul disco del server).
L'applicazione Java (la servlet) potrà quindi svolgere tutte
le sue funzioni attingendo agli oggetti già presenti nei vari
contenitori (nella sessione, ad esempio) o mettendocene di
nuovi.
Risposta
Al termine del proprio lavoro la Servlet deve dare un
esito al proprio lavoro tramite la risposta Res. Le uniche
- 65 -
CAP. 4 - TECNOLOGIE SOFTWARE
due modalità per farlo sono o riempirla con dei contenuti
che il client sia in grado di comprendere (codice HTML, ad
esempio) oppure inserire un ordine per il contesto di
redirigere il controllo ad un'altra risorsa (forward).
Nel primo caso il contesto ripasserà tutto l'oggetto a
Tomcat che si occuperà di generare l'output per il client.
Nel secondo caso, se la risorsa è esterna al contesto il
controllo verrà restituito a Tomcat che ricomincerà il
percorso logico con questa nuova risorsa. Se invece la
risorsa è interna al contesto un'operazione di forward
equivale a fare un passo indietro nel percorso logico per poi
tornare avanti su un altro sentiero o, in altri termini,
chiamare
la
Servlet
associata
alla
risorsa
indicata
nell'istruzione di forward, passandole nuovamente tutto
l'ambiente.
- 66 -
CAP. 4 - TECNOLOGIE SOFTWARE
Tomcat
è
un
Servlet/JSP
engine,
o
meglio,
è
l'implementazione ufficiale delle specifiche di queste due
tecnologie, che permette di eseguire Servlet e pagine JSP
su richiesta di un utente. Esso può essere usato da solo
(principalmente
utile
agli
sviluppatori
per
testing
e
debugging) o in congiunzione con uno tra i più diffusi web
server (per le applicazioni real world), tra i quali:
• Apache, versione 1.3 o successiva
• Microsoft Internet Information Server
• Microsoft Personal Web Server
• Netscape Enterprise Server
Quindi in base alle esigenze di utilizzo si dovrà installare
anche un web server con cui Tomcat coopererà: quando
arriva una richiesta di esecuzione di una servlet o JSP, il
web server la passa a Tomcat che si occupa di esaudirla.
Installazione di Apache Tomcat
Tomcat richiede per il suo funzionamento un Java
Runtime Enviroment JRE 1.1 o successivo, (compresi,
naturalmente i sistemi basati sulla piattaforma Java2).
- 67 -
CAP. 4 - TECNOLOGIE SOFTWARE
Scaricare l'archivio nel formato più adatto al proprio
sistema operativo da qui (Jakarta, il sito ufficiale di
Tomcat).
Spacchettare l'archivio in una directory (chiamiamola ad
esempio foo) dove verrà creata una subdirectory di nome
jakarta-tomcat-5.5.9.
Variabili d'ambiente
Cambiare directory spostandosi in jakarta-tomcat-5.5.9e
settare la variabile d'ambiente TOMCAT_HOME in modo da
farla puntare alla directory radice dove Tomcat è stato
installato.
Su
Windows
utilizzare
set
TOMCAT_HOME=C:\foo\jakarta-tomcat-5.5.9
supponendo
che Tomcat sia stato installato sul disco C.
Su
Unix
utilizzare
per
TOMCAT_HOME=/foo/jakarta-tomcat-5.5.9;
TOMCAT_HOME
per
tcsh
setenv
bash/sh
export
TOMCAT_HOME
/foo/jakarta-tomcat-5.5.9supponendo che Tomcat si stato
installato in /foo.
Settare la variabile d'ambiente JAVA_HOME in modo che
punti alla directory radice dove è installato il JDK e infine
- 68 -
CAP. 4 - TECNOLOGIE SOFTWARE
aggiungere
il
path
dell'interprete
java
alla
variabile
d'ambiente PATH. Tomcat è pronto adesso per essere
eseguito in modalità stand-alone (da solo senza web
server).
Avvio e arresto di Tomcat
Per avviare Tomcat usare lo script o il file batch che si
trovano nella directory TOMCAT_HOME/bin.
Su UNIX utilizzare % startup.sh
Su Windows utilizzare C:\TOMCAT_HOME\bin>startup
Per arrestare Tomcat, ci sono due comandi che si
trovano nella stessa directory dei comandi di avvio.
Su UNIX utilizzare % shutdown.sh
Su Windows utilizzare C:\TOMCAT_HOME\bin>shutdown
La struttura delle directory di Tomcat
Vediamo come è struturata la gerarchia delle directory di
Tomcat
a
partire
dalla
radice.
Dopo
avere
unzippato/untarato Tomcat si pùò vedere che all'interno
della directory jakarta-tomcat-5.5.9 abbiamo:
- 69 -
CAP. 4 - TECNOLOGIE SOFTWARE
Tabella 1. Struttura delle directory
Nome della directory Descrizione
bin Contiene gli script/batch per lo startup-shutdownd
conf Contiene i file di configurazione tra cui server.xml
che è il principale file di configurazione di Tomcat, e
web.xml che serve a settare i valori di default per le varie
applicazioni gestite da Tomcat
doc Contiene vari documenti riguardanti Tomcat
lib Contiene diversi file jar usati da Tomcat . Su UNIX
ogni file in questa directory viene appeso al classpath.
logs Directory utilizzata per i file di log
src Sorgenti delle interfacce e delle classi astratte delle
API servlet.
webapps Contiene esempi di applicazioni web
In aggiunta a queste directory si possono avere anche
altre due directory: classes creata dall'utente, dove si
possono mettere classi che Tomcat aggiungerà, al suo
avvio, al classpath; e work generata automaticamente da
Tomcat come directory temporanea (ad esempio per
contenere le pagine JSP già compilate, prima di inviarle al
client). Se si cancella questa directory quando Tomcat è
attivo, non si potranno eseguire pagine JSP.
Conclusioni
- 70 -
CAP. 4 - TECNOLOGIE SOFTWARE
Se tutto è andato liscio Tomcat dovrebbe funzionare.
Provate a testare le applicazioni già installate, ad esempio
http://ind_host:8080/examples/jsp/
oppure
http://ind_host:8080/examples/servlets/ (dove ind_host è
l'indirizzo IP o il nome della macchina dove è installato
Tomcat, oppure usa localhost se è la stessa da cui ti
colleghi). Da queste due pagine si possono testare diverse
pagine JSP e servlet, con la possibilità di vedere dal
browser stesso anche il codice degli esempi proposti.
4.2.1 Comunicazione SSL
Il protocollo SSL utilizza combinazioni di chiavi pubbliche
e simmetriche. Una sessione SSL inizia con uno scambio di
messaggi
effettuati
nella
fase
detta
“Handshake”.
Vediamola in dettaglio.
Fig. 4.1 – Comunicazione Diretta SSL
Il server ha un certificato che descrive le informazioni
riguardanti la società/ente/persona. I campi più rilevanti
sono le informazioni di cui sopra e la chiave pubblica. Il
tutto è regolato dal Certificato X.509. Tale certificato può
essere garantito da una Certification Authority, la quale
- 71 -
CAP. 4 - TECNOLOGIE SOFTWARE
assicura l’esatta corrispondenza tra il certificato e colui che
lo emette. Anche il client può avere un certificato, ma
questo serve solo se esso deve ricevere dati sensibili da
parte del server. Generalmente è il contrario.
Se la connessione è iniziata dal server, esso invierà al
client un messaggio “server hello”. Se è il client ad iniziare
la connessione, si avrà in invio un messaggio “hello”.
Analizziamo più in dettaglio tale messaggio.
È definito dai campi:
1. protocol version: definisce la versione SSl usata;
2. random byte: byte casuali generati dal client;
3. Session identifier: per verificare se si tratta di una
nuova sessione o di una aperta in precedenza;
4. Lista delle CipherSuite: è una lista in cui il Client
notifica al Server gli algoritmi di crittografia supportati,
ordinati in modo decrescente;
5. Lista degli algoritmi di compressione, supportati dal
Client.
Il Server risponde con un messaggio “server hello” definito
nel modo seguente:
1. Protocol version: rappresenta la versione SSl scelta
dal Server;
2. Random byte: byte generati in modo casuale;
3. Session identifier: identifica la sessione. Se non è una
sessione già aperta, se ne crea una nuova; questo nel
caso in cui nel tag “session identifier” del messaggio
- 72 -
CAP. 4 - TECNOLOGIE SOFTWARE
“hello”
sino
presenti
tutti
zeri;
Altrimenti
viene
riesumata la sessione indicata dal client, se presente
nella cache del server;
4. ChiperSuite: famiglia di algoritmi di crittografia scelta
dal server;
5. Compression method: metodo di compressione scelto
da server.
Dopo
questo
l’autenticazione
scambio
tramite
lo
di
messaggi,
scambio
di
un
avviene
certificato.
Supponiamo che debba essere il server ad identificarsi.
Questo vuol dire che i dati confidenziali transiteranno dal
client al server e NON viceversa, in quanto il Client non è
identificato. Tale situazione potrebbe essere, per esempio,
una fase di acquisto in rete, in cui il client invia i suoi dati
personali al Server, quindi è necessario che il Server sia
ben identificato. Il Server dunque invia il certificato al
Client, insieme alle preferenze riguardo l’algoritmo di
crittografia da usare. A questo punto il client verifica che il
certificato ricevuto sia valido analizzando vari aspetti. Per
prima cosa la data di validità del certificato. In seguito, si
verifica che la CA che garantisce il certificato (ammesso che
ce ne sia una), sia una CA affidabile. Se lo è, il client
recupera la chiave pubblica dalla sua lista di CA sicure per
verificare la firma digitale arrivatagli con il certificato del
server. Se l’informazione in tale certificato è cambiata da
quando è stata firmata da una CA, o se la chiave pubblica
- 73 -
CAP. 4 - TECNOLOGIE SOFTWARE
nella lista CA non corrisponde alla chiave privata usata dalla
CA per firmate il certificato del server, il client non potrà
autenticare il server. Infine, il client verifica che il nome del
dominio nel certificato server
corrisponda
allo
stesso
dominio del server. Questa fase conferma che il server è
localizzato nello stesso indirizzo di rete che è specificato nel
nome di dominio del suo certificato. Tale controllo previene
attacchi del tipo “Man in the Middle”, in quanto se il domain
name non corrisponde, molto probabilmente perché il
certificato è stato inviato non dal server atteso, ma da una
terza persona che si è intromessa. La connessione sarà
rifiutata se i due nomi non corrispondono. Se invece tutto è
andato a buon fine, il client avrà verificato che il server è
affidabile.
A questo punto il client genera una “pre master key” e la
cripta con la chiave pubblica del server.
Opzionalmente, in questa fase, può essere richiesta
l’autenticazione del client, che è molto simile a quella vista
prima, nel seguente modo: esso deve cifrare alcuni valori
casuali condivisi con la sua chiave privata, creando in
pratica una firma. In più, il server verifica che il client,
anche se autenticato, sia autorizzato ad accedere alle
risorse richieste. La chiave pubblica nel certificato del client
può facilmente convalidare tale firma se il certificato è
autentico, in caso contrario la sessione sarà terminata. Il
server riceve il messaggio criptato e, verificata l’attendibiltà
del client, lo decripta tramite la sua chiave privata. Genera
- 74 -
CAP. 4 - TECNOLOGIE SOFTWARE
poi una master secret (cosa che fa anche il client, seguendo
gli stessi passi) e da questa, insieme, generano la chiave di
sessione, una chiave simmetrica che sarà usata per criptare
e decriptare i dati che attraversano il tunnel SSL appena
creato; inoltre serve per verificare che i dati non vengano
alterati nel lasso di tempo che intercorre tra l’invio e la
ricezione. A questo punto il client ed il server si inviano un
messaggio di notifica di HandShake concluso, e lo scambio
di dati può iniziare.
Fig. 4.2 – Attacco nel mezzo
Installazione e configurazione del supporto SSL su
Tomcat 5
1. Creare un keystore eseguendo il seguente
comando:
Windows:
%JAVA_HOME%\bin\keytool -genkey -alias
tomcat -keyalg RSA
Unix:
$JAVA_HOME/bin/keytool -genkey -alias tomcat
-keyalg RSA
- 75 -
CAP. 4 - TECNOLOGIE SOFTWARE
and specify a password value of "changeit".
Scommentare l’elemento "SSL HTTP/1.1 Connector"
nel file di configurazione di Tomcat
$CATALINA_HOME/conf/server.xml e modificarlo
come necessario.
<-- Define a SSL Coyote HTTP/1.1 Connector
on port 8443 -->
<!-- <Connector
port="8443" minProcessors="5"
maxProcessors="75"
enableLookups="true"
disableUploadTimeout="true"
acceptCount="100" debug="0"
scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS"
/> -->
2. Usare l’attributo keystoreFile per specificare il
percorso del “.keystore”.
Attenzione nello specificare un percorso relativo per
il file di keystore perchè si parte dalla cartella di
installazione del Tomcat mentre il keytool parte
dalla cartella base dell’utente inoltre se si usa
l’Eclipse è necessario copiare il keystore anche nella
cartella
dello
workspace
“.metadata\.plugins\org.eclipse.wst.server.core\tmp
- 76 -
CAP. 4 - TECNOLOGIE SOFTWARE
0” altrimenenti quando viene lanciato il Tomcat in
Eclipse non trova il file (bisogna apportare le stesse
modifiche
fatte
al
file
di
configurazione
$CATALINA_HOME/conf/server.xml anche sul file
server.xml del Server project di Eclipse).
Si
può
notare
che
l’elemento
Connector
stesso
è
commentato di default, quindi è necessario rimuovere i tag
di
commento
che
lo
circondano.
Poi,
è
possibile
personalizzare gli attributi specificati come necessario. La
discussione seguente analizza solo gli attributi di maggiore
interesse per impostare la comunicazione SSL, per il resto
delle opzioni si può fare riferimento alla guida del Tomcat.
L’attributo port (valore di default è 8443) è il numero
della porta TCP/IP sulla quale Tomcat si metterà in ascolto
per le connessioni sicure. Può essere cambiare con un
qualisiasi numero di porta (come con la porta di default per
le communicazioni https, che è il 443). Comunque, speciali
setup (che non andiamo ad analizzare) necessitano di
eseguire Tomcat su numeri di porta minori di 1024 su molti
sistemi operativi.
If you change the port number here, you should
also change the value specified for the redirectPort
attribute on the non-SSL connector. This allows
Tomcat
to
automatically
redirect
- 77 -
users
who
CAP. 4 - TECNOLOGIE SOFTWARE
attempt
to
access
a
page
with
a
security
constraint specifying that SSL is required, as
required by the Servlet 2.4 Specification.
Ci sono opzioni aggiuntive usate per configurare il
protocollo SSL. Potrebbe essere necessario aggiungere o
cambiare un valore dei seguenti attributi, a seconda di
come è stato precedentemente configurato il keystore:
NOME
ATTRIBUTO
DESCRIZIONE
Impostare il valore a true se si vuole che il
Tomcat richieda ai client SSL di presentare
un Certificato client per poter usare questo
clientAuth
socket. Impostare il valore want se si
vuole che il Tomcat richieda un Certificato
client, ma non ritorni errore nel caso non
venga presentato.
Aggiungere questo attributo se il file del
keystore creato non è nel percorso di
default che si aspetta Tomcat (un file
keystoreFile
chiamato .keystore nella cartella user
home sotto la quale Tomcat è in
esecuzione). Può essere specificato un
percorso assoluto, o uno relativo che viene
risolto a partire dalla variabile di ambiente
- 78 -
CAP. 4 - TECNOLOGIE SOFTWARE
$CATALINA_BASE.
Aggiungere questo elemento se è stata
keystorePass
usata una password del keystore (e del
certificato) differente da quella che si
aspetta Tomcat (changeit).
Aggiungere questo elemento se si sta
keystoreType
usando un keystore PKCS12. I valori
possibili per questo attributo sono JKS e
PKCS12.
Il protocollo di crittografia/decrittografia
che deve essere usato su questa socket.
Non è consigliato cambiare questo valore
sslProtocol
se si sta utilizzando la JVM di Sun. È stato
riportato che nell’implementazione1.4.1 di
IBM il protocollo TLS non è compatibile con
alcuni diffusi browser. In questo caso,
usare il valore SSL.
La lista, separata da virgola, di cifre di
ciphers
crittografia che a questa socket è
consentito usare. Di default, qualsiasi cifra
disponibile è consentita.
L’algoritmo X509 da usare. Il default è
impostato all’implementazione Sun
algorithm
(SunX509). Per le JVM di IBM il valore
dovrebbe essere impostato a IbmX509.
Per altri fornitori, consultare la
- 79 -
CAP. 4 - TECNOLOGIE SOFTWARE
documentazione JVM per il valore corretto.
truststoreFile
Il file di TrustStore da usare per validare i
certificate dei client.
La password per accedere al TrustStore. Il
truststorePass default è impostato al valore dell’attributo
keystorePass.
Dopo
aver
completato
queste
modifiche
alla
configurazione, è necessario riavviare il Tomcat come si fa
normalmente, e tutto dovrebbe essere pronto. Dovrebbe
essere
possibile
accedere
attraverso
SSL
a
qualsiasi
applicazione web supportata da Tomcat. Per esempio, si
può provare con:
https://localhost:8443
e dovrebbe essere visualizzata la pagina di introduzione
del Tomcat (a meno che non sia stato cambiato il ROOT
dell’applicazione web).
Configurazione della Web Application, file web.xml
// Impostazione del keyStore
System.setProperty("javax.net.ssl.keyStore","D:/J
Telemed/.keystore");
System.setProperty("javax.net.ssl.keyStorePasswor
d","changeit");
- 80 -
CAP. 4 - TECNOLOGIE SOFTWARE
<security-constraint>
<web-resource-collection>
<web-resource-name>JTelemedSite</web-resourcename>
<url-pattern>/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transportguarantee>
</user-data-constraint>
</security-constraint>
<login-config>
<auth-method>CLIENT-CERT</auth-method>
<realm-name>JTelemed</realm-name>
</login-config>
Configurazione del Tomcat, file server.xml
- 81 -
CAP. 4 - TECNOLOGIE SOFTWARE
<!-- Define a SSL HTTP/1.1 Connector on port 8443
-->
<Connector keystoreFile=".keystore"
keystorePass="changeit" clientAuth="true"
acceptCount="100" disableUploadTimeout="true"
enableLookups="false"
maxHttpHeaderSize="8192" maxSpareThreads="75"
maxThreads="150"
minSpareThreads="25" port="8443" scheme="https"
secure="true"
sslProtocol="TLS"/>
Configurazione del Web Service, file web.xml
<security-constraint>
<web-resource-collection>
<web-resource-name>JTelemedSite</web-resourcename>
<url-pattern>/services/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transportguarantee>
- 82 -
CAP. 4 - TECNOLOGIE SOFTWARE
</user-data-constraint>
</security-constraint>
<login-config>
<auth-method>CLIENT-CERT</auth-method>
<realm-name>JTelemed</realm-name>
</login-config>
- 83 -
CAP. 4 - TECNOLOGIE SOFTWARE
4.3 STRUMENTI DI SVILUPPO
4.3.1 Apache Struts
Il modello di sviluppo più diffuso per la realizzazione del
front-end di applicazioni web mediante il linguaggio Java è
sicuramente quello delle JSP (Java Server Pages): con
questa
tecnologia
separazione
tra
viene
implementato
interfaccia
utente
e
un
pattern
generazione
di
del
contenuto.
L'obiettivo è permettere al designer Html di cambiare il
layout complessivo della pagina a prescindere dal suo
contenuto, che verrà generato poi dinamicamente a runtime, tramite accesso ad un Dbms o ad altri meccanismi di
persistenza delle informazioni.
Questo modello ha da un lato il pregio assoluto della
semplicità di comprensione e di utilizzo (la pagina Jsp viene
poi compilata in una servlet e gestita dall'application server
in modo trasparente al programmatore) ma dall'altro non è
sufficientemente attrezzato per affrontare applicazioni che
vadano oltre una certa complessità.
Mancano infatti logiche sufficientemente sofisticate di
ripartizione dei ruoli all'interno dei programmi applicativi da
un lato e di controllo complessivo del set delle pagine
costruite dall'altro. Si può cercare di superare questa
- 84 -
CAP. 4 - TECNOLOGIE SOFTWARE
difficoltà utilizzando un adattamento all'ambiente web di un
pattern ben noto di costruzione di applicazioni interattive: il
cosiddetto Model-View-Controller.
Secondo questo pattern, i componenti di un'applicazione
vengono logicamente classificati a seconda che siano
gestori di logiche di business e di accesso ai dati (model),
gestori
di
visualizzazione
dati
e
dell'input
dell'utente
(viewer o view) e gestori del flusso di controllo complessivo
dell'applicazione (controller).
Fig. 4.3 – View Model
Nel mondo Java, questo pattern viene generalmente
indicato come Model2 (dove per Model1 si intende per
retrocompatibilità
standard
di
la
generalizzazione
funzionamento
implementazione
di
delle
riferimento
si
della
JSP):
ha
modalità
una
in
sua
Struts,
sottoprogetto del Jakarta Project; il progetto della Apache
- 85 -
CAP. 4 - TECNOLOGIE SOFTWARE
software Foundation che raccoglie tecnologie basate su
Java per utilizzi specifici web.
Struts è uno strato software di controllo flessibile, che
utilizza
tecnologie
standard
ResourceBundles)
e
programmatore
un
Xml
e
Java
mette
(Servlet,
a
controller
Beans,
disposizione
sofisticato
del
per
l'implementazione pratica del pattern Model2.
Il notevole vantaggio di questa astrazione è che Struts è
essenzialmente agnostico rispetto alle scelte di chi faccia
poi il model ed il view. In pratica vengono utilizzati
componenti Ejb oppure Jdbc o plain Jdo per costruire il
model, mentre per il view si lavora ancora con le Jsp (a
questo punto viste come componenti di un framework più
"robusto"
e
non
come
costituenti
l'intero
framework
applicativo a disposizione del programmatore) o con altri
sistemi di template come Velocity o Xslt.
Fig. 4.4 – Struttura di Struts
- 86 -
CAP. 4 - TECNOLOGIE SOFTWARE
In sostanza, un'applicazione web basata su Struts utilizza
un
deployment
descriptor
(descrittore
dell'impiego
dell'applicazione: fisicamente si tratta di un documento
Xml)
per
inizializzare
dell'applicazione;
ActionForms,
l'interzione
risorse
che
che
tra
includono
raccolgono
le
risorse
principalmente
l'input
dall'utente,
ActionMappings che indirizzano poi l'input ad opportune
Actions
(programmi
server-side,
senza
funzionalità
di
presentazione) e ActionForwards che selezionano le pagine
di output indicate.
Anche la validazione dell'input utente può essere definita
in fase di deployment attraverso un'altro descrittore Xml
utilizzato dalle risorse ActionForms: lo Struts Validator.
Abbiamo
quindi
un
esempio
di
approccio
alla
realizzazione di sistemi di tipo extremely late binding, dove
addirittura alcune scelte sul workflow complessivo del
sistema
possono
essere
riconsiderate
in
fase
di
deployment: questo tipo di logica garantisce la massima
flessibilità nell'utilizzo dei componenti base dell'applicazione
e permette di affrontare situazioni dove venga richiesta una
notevole
complessità
nella
dell'applicazione.
- 87 -
presentazione
web
CAP. 4 - TECNOLOGIE SOFTWARE
Fig. 4.5 – Flusso di struts
• Request: Richiesta HTTP
• Dispatch: Chiama una action passandogli il form bean
creato
• Update: Crea un form bean con i dati della form HTML
• Forward: Chiama una pagina JSP
• Extract: Crea un bean con i dati risultanti
• Response: Produce una risposta HTTP
- 88 -
CAP. 5 - CRITTOGRAFIA
A
CHIAVE PUBBLICA
CAPITOLO 5
CRITTOGRAFIA A CHIAVE
PUBBLICA
Descrizione delle tecniche di crittografia dei
dati digitali e di firma digitale, utilizzo dei
certificati.
5.1 Crittografia
5.1.1 Introduzione
5.1.2 Crittografia a chiave simmetrica
5.1.3 Sistemi a crittografia a chiave pubblica
5.2 La firma digitale
5.2.1 Algoritmo RSA
5.2.2 Algoritmo SHA-1
5.3 Certificati elettronici
5.3.1 Standard X.509 per i certificati
5.3.2 Necessità di coppie di chiavi distinte
per cifratura e firma
5.4 Infrastruttura a chiave pubblica (PKI)
5.4.1 Requisiti di una PKI
5.5 Gestione dei certificati
5.5.1 Ciclo di vita dei certificati
- 89 -
CAP. 5 - CRITTOGRAFIA
5.5.2 La gestione delle chiavi
5.5.3 La revoca di un certificato
5.5.4 I cammini di certificazione
- 90 -
A
CHIAVE PUBBLICA
CAP. 5 - CRITTOGRAFIA
A
CHIAVE PUBBLICA
5.1 CRITTOGRAFIA
5.1.1 Introduzione
La crittografia è lo studio della codifica e della decodifica
dei dati. Il termine crittografia viene dalle parole greche
kryptos che significa nascosto, e graphia, che significa
scrittura.
La crittografia riveste un ruolo preminente nell'ambito dei
meccanismi di sicurezza, essendo in grado di fornire la
maggior parte dei servizi contemplati nell'architettura di
sicurezza stabilita dall’ISO (International Organization for
Standardization); pertanto i sistemi crittografici rivestono
un’importanza
fondamentale
nella
soluzione
di
molte
problematiche di sicurezza connesse con la protezione di
informazioni.
Per inquadrare il problema è opportuno rifarsi al modello
di riferimento proposto dall’ISO che individua cinque classi
di funzionalità necessarie per garantire il desiderato livello
di sicurezza. Queste sono:
1. confidenzialità: con tale funzionalità si vuole impedire di
rilevare informazioni riservate ad entità non autorizzate
alla conoscenza di tali informazioni; la confidenzialità è
- 91 -
CAP. 5 - CRITTOGRAFIA
A
CHIAVE PUBBLICA
ottenuta tramite tecniche crittografiche di cifratura dei
dati.
2. integrità dei dati: i servizi di integrità dei dati proteggono
contro
gli
attacchi
attivi
finalizzati
ad
alterare
illegittimamente il valore di un dato; l’alterazione di un
messaggio
può
comprendere
la
cancellazione,
la
modifica, o il cambiamento dell’ordine dei dati
3. autenticazione: i servizi di autenticazione garantiscono
l’accertamento dell’identità; quando a qualcuno (o a
qualcosa) si attribuisce una certa identità, i servizi di
autenticazione forniscono lo strumento con cui verificare
la correttezza di tale affermazione di identità; i servizi di
autenticazione si suddividono in:
- servizi di autenticazione dell’entità: in questo caso si
autentica l’identità presentata ad un entità remota che
partecipa
ad
una
sessione
di
comunicazione
(le
password sono un esempio tipico di strumenti atti ad
ottenere autenticazione dell’entità).
- servizi di autenticazione dell’origine dei dati: in questo
caso si autentica l’identità che l’originatore di un
messaggio rivendica di avere;
4. controllo degli accessi: una volta che l’autenticazione è
avvenuta, è possibile eseguire un controllo degli accessi
in modo tale da verificare che vengano utilizzate solo
quelle risorse o servizi ai quali si è autorizzati.
5. non ripudio: tali servizi hanno la finalità di impedire che
un’entità
riesca
successivamente
- 92 -
a
rinnegare
con
CAP. 5 - CRITTOGRAFIA
successo
la
partecipazione
a
A
CHIAVE PUBBLICA
transazione
o
comunicazione a cui in realtà ha preso parte; i servizi di
non
ripudio
non
prevengono
il
ripudio
di
una
comunicazione o di una transazione, forniscono, invece,
gli elementi per dimostrare in caso di contenzioso
l’evidenza dei fatti. Se è vero che autenticazione ed
integrità
dei
dati
sono
elementi
essenziali
nell’implementazione di un servizio di non ripudio senza,
il non ripudio, tuttavia, va oltre le problematiche di
autenticazione ed integrità: è, infatti, lo strumento con
cui dimostrare ad una terza parte e dopo l’accadimento
del fatto che una comunicazione o transazione è stata
originata o avviata da una certa entità o consegnata ad
una certa entità. Si pensi ad esempio al caso di una
persona, Alice, che invia un ordine di acquisto di beni a
Bob; la paternità dell’ordine di acquisto viene attribuita
con assoluta certezza ad Alice se si adotta un servizio
corretto di non ripudio; in caso di contenzioso Bob può
dimostrare con assoluta certezza che l’ordine di acquisto
è stato effettuato da Alice. Nei documenti cartacei, quali
contratti, ordini, bonifici, è la firma autografa ad essere
utilizzata per garantire il servizio di non ripudio, nei
documenti elettronici è, invece, la tecnica crittografica di
firma digitale.
Le principali tecniche crittografiche, cifratura e firma
digitale,
costituiscono
i
- 93 -
componenti
basilari
CAP. 5 - CRITTOGRAFIA
A
CHIAVE PUBBLICA
nell’implementazione di tutti i servizi di sicurezza sopra
descritti. Alla base delle tecniche crittografiche si colloca
l’algoritmo
crittografico
che
fornisce
le
funzioni
di
trasformazione di un testo da testo in chiaro a testo cifrato.
Gli algoritmi crittografici si suddividono in due classi
distinte: algoritmi a chiave simmetrica e algoritmi a chiave
pubblica. Fino a poco più di vent’anni fa erano conosciuti
solo gli algoritmi a chiave simmetrica; nel 1976 Diffie ed
Hellman presentarono un protocollo per lo scambio di una
chiave
segreta
attraverso
un
canale
insicuro;
tale
meccanismo era stato inteso essenzialmente per risolvere il
problema dell’avvio di un normale sistema di cifratura a
chiavi simmetriche ma in realtà ha posto le basi della
crittografia a chiave pubblica.
5.1.2 Crittografia a chiave simmetrica
Gli algoritmi simmetrici utilizzano una singola chiave
matematica sia per la cifratura che per la decifratura dei
dati. Un messaggio sicuro viene cifrato per il destinatario
utilizzando una chiave nota solamente al mittente ed al
destinatario.
Il
principio
matematico
su
cui
si
basa
l’algoritmo è che cifrando un testo in chiaro con una certa
chiave si ottiene nuovamente il testo in chiaro (vedi Figura
1):
- 94 -
CAP. 5 - CRITTOGRAFIA
A
CHIAVE PUBBLICA
Dk (Ek (P )) = P
con P = testo in chiaro, E = operazione di cifratura,
D = operazione di decifratura, K = chiave
Fig. 5.1: Schema di funzionamento di un algoritmo
simmetrico
Il principale problema implementativo di algoritmi a
chiave simmetrica è dovuto alla difficoltà di distribuire le
chiavi in modo sicuro e su larga scala. Infatti, l’intera
sicurezza dell’algoritmo si basa sulla segretezza della chiave
che deve essere conosciuta solo dai due interlocutori e
pertanto si pone il problema di come poter distribuire tale
chiave in maniera sicura ( non si potranno utilizzare canali
intrinsecamente insicuri come, ad esempio,Internet).Inoltre
, se si assume che una chiave distinta è richiesta per ogni
coppia di interlocutori, il numero di chiavi da distribuire
aumenta drasticamente all’aumentare delle parti in gioco;
se, infatti , n sono le parti coinvolte , il numero di chiavi da
distribuire è pari a n*(n-1)/2. A questo va aggiunto che un
protocollo di comunicazione che utilizza crittografia a chiave
- 95 -
CAP. 5 - CRITTOGRAFIA
A
CHIAVE PUBBLICA
simmetrica non mette a disposizione che garantiscono
l’integrità e l’autenticazione dell’origina dei dati. Infatti , un
intrusore che riesce a conoscere la chiave segreta di due
interlocutori , può poi , intercettando i messaggi scambiati ,
alterarne il contenuto , inficiandone cossi l’integrità . Inoltre
, il destinatario non è più in grado di distinguere se i
messaggi provengono dal mittente originale o dall’ intrusore
e quindi non ha più nessuna garanzia di autenticazione.
Gli algoritmi simmetrici più diffusi sono CAST , DES ,
Triple DES, RC2, RC4, RC5, IDEA.
5.1.3 Sistemi a crittografia a chiave pubblica
Gli algoritmi a chiave pubblica (altrimenti detti asimmetrici)
, sono progettati in modo tale che la chiave di cifratura
risulta differente dalla chiave di decifratura. Quello che
viene cifrato con la chiave di cifratura, chiave pubblica, può
essere decifrato solo con l’altra chiave di decifratura , detta
chiave privata.
La conoscenza della chiave pubblica non permette di
determinare quella privata (si tratta di un problema
computazionalmente complesso). Questo è il motivo per cui
la chiave di decifratura può essere resa pubblica senza
compromettere la sicurezza del sistema.
C= E(Kpub , P) P= D(Kpriv ,C)
P = testo in chiaro, C = testo cifrato
- 96 -
CAP. 5 - CRITTOGRAFIA
A
CHIAVE PUBBLICA
E = operazione di cifratura, Kpub = chiave pubblica del
destinatario
D = operazione di decifratura, Kpriv = chiave privata del
destinatario
Fig. 5.2: Schema di funzionamento di un algoritmo a
chiave pubblica
Con tali algoritmi, a differenza di quelli simmetrici, non è
più
necessario
prevedere
un
canale
sicuro
per
la
trasmissione della chiave, in quanto, essendo la chiave di
decifratura distinta da quella di cifratura, è possibile
distribuire quest’ultima in maniera non riservata tramite dei
server pubblici. Se, poi, n sono gli utenti coinvolti, n è
anche il numero di chiavi da distribuire e non n*(n-1)/2
come nel caso degli algoritmi simmetrici.
Gli algoritmi asimmetrici garantiscono la confidenzialità
nella comunicazione. Infatti, un messaggio cifrato con la
chiave pubblica del destinatario fa sì che solo quest’ultimo
sia in grado di decifrare tale messaggio, in quanto è l’unico
che possiede la corrispondente chiave privata. Inoltre
- 97 -
CAP. 5 - CRITTOGRAFIA
A
CHIAVE PUBBLICA
invertendo l’utilizzo delle chiavi, ossia cifrando con la chiave
privata del mittente e decifrando con la chiave pubblica del
mittente, è possibile garantire l’autenticazione. È su tale
principio che si basa la firma digitale.
- 98 -
CAP. 5 - CRITTOGRAFIA
A
CHIAVE PUBBLICA
5.2 LA FIRMA DIGITALE
Fino a pochissimo tempo fa la firma autografa era
considerata
l’unico
strumento
adeguato
per
attribuire
certezza la paternità di un messaggio: un documento
originale, stampato su carta e firmato in maniera autografa,
è ritenuto, infatti, legalmente valido. Tale validità legale è
attribuita ritenendo che:
• Sia possibile rilevare alterazioni o abrasioni della carta
che ne indicono una contraffazione.
• Sia possibile ricondurre con certezza (quantomeno
“legale”) la firma apposta in calce ad un documento
alla
persona
manifestazione
la
cui
della
firma
sua
è
apposta,
volontà
di
e
alla
sottoscrivere
accettare o richiedere quanto esposto nel documento
stesso.
La certezza dell’autenticità della firma, come è ben
evidente a chiunque abbia falsificato la firma di un
conoscente,
è
assai
lontana
dalla
realtà.
Nonostante
questo, la legge tutela questa forma di manifestazione della
volontà e la considera talmente valida da richiedere che
certi documenti, di cui si ipotizza una eventuale futura
contestazione, debbano essere conservati per lunghi periodi
di tempo.
- 99 -
CAP. 5 - CRITTOGRAFIA
A
CHIAVE PUBBLICA
La firma digitale (digital signature), invece, è, oggi, la
tecnologia con cui possono essere effettivamente soddisfatti
tutti i requisiti richiesti per dare validità legale ad un
documento elettronico firmato digitalmente; garantisce i
servizi di integrità, autenticazione e non ripudio.
Vediamo quali sono le proprietà richieste al processo di
apposizione di una firma digitale (proprietà che nel caso
della firma autografa si assume siano garantite):
• non falsificabili: la firma è la prova che solo il
firmatario nessun altro ha apposto la firma sul
documento.
• non riusabilità: la firma fa parte integrante del
documento non deve essere utilizzabile su un altro
documento.
• non alterabilità: una volta firmato, il documento non
deve poter essere alterato.
• non contestabilità: il firmatario non può rinnegare con
successo la paternità dei documenti firmati; la firma
attesta la volontà del firmatario di sottoscrivere
quanto contenuto nel documento.
La
firma
crittografiche
digitale
a
viene
chiave
realizzata
pubblica
tramite
insieme
tecniche
all’utilizzo
di
particolari funzioni matematiche, chiamate funzioni hash
unidirezionali. Il processo di firma digitale passa attraverso
tre fasi:
- 100 -
CAP. 5 - CRITTOGRAFIA
A
CHIAVE PUBBLICA
1. Generazione dell’impronta digitale
2. Generazione della firma
3. Apposizione della firma
Nella prima fase viene applicata al documento in chiaro
una funzione di hash appositamente studiata che produce
una
stringa
binaria
di
lunghezza
costante
e
piccola,
normalmente 128 o 160 bit, chiamata digest message o
digital fingerprint ossia impronta digitale. Queste funzioni
devono avere due proprietà:
• unidirezionalità, ossia dato x è facile calcolare f(x), ma
data f(x) è computazionalmente difficile risalire a x.
• prive di collisioni (collision-free), ossia a due testi
diversi deve essere computazionalmente impossibile
che corrisponda la medesima impronta. ( x ≠ y allora
f(x) ≠ f(y) )
- 101 -
CAP. 5 - CRITTOGRAFIA
A
CHIAVE PUBBLICA
Figura 1.3: Schema di funzionamento di una funzione
hash
L’utilità dell’uso delle funzioni hash consente di evitare
che per la generazione della firma sia necessario applicare
l’algoritmo di cifratura, che è intrinsecamente inefficiente,
all’intero
testo
che
può
essere
molto
lungo.
Inoltre
consente l’autenticazione, da parte di una terza parte
fidata, della sottoscrizione di un documento senza che
questa venga a conoscenza del suo contenuto1. La seconda
fase, la generazione della firma, consiste semplicemente
nella cifratura con la propria chiave privata dell’impronta
digitale generata il precedenza. In questo modo la firma
risulta legata, da un lato (attraverso la chiave privata usata
per la generazione) al soggetto sottoscrittore, e dall’altro
(per il tramite dell’impronta) al testo sottoscritto. In realtà
l’operazione di cifratura viene effettuata, anziché sulla sola
impronta, su una struttura di dati che la contiene insieme
- 102 -
CAP. 5 - CRITTOGRAFIA
A
CHIAVE PUBBLICA
con altre informazioni utili, quali ad esempio l’indicazione
della funzione hash usata per la sua
generazione. Sebbene tali informazioni possano essere
fornite separatamente rispetto alla firma, la loro inclusione
nell’operazione di codifica ne garantisce l’autenticità.
Nell’ultima fase, la firma digitale generata precedentemente
viene aggiunta in una posizione predefinita, normalmente
alla fine, al testo del documento. Di solito, insieme con la
firma vera e propria, viene allegato al documento anche il
valore dell’impronta digitale ed eventualmente il certificato2
da cui è possibile
recuperare il valore della chiave pubblica.
La firma digitale così generata viene aggiunta in una
posizione predefinita, normalmente alla fine, al testo del
documento. Normalmente, insieme con la firma vera e
propria,viene
allegato
al
documento
anche
il
valore
dell’impronta digitale ed eventualmente il certificato da cui
è possibile recuperare il valore della chiave pubblica.
L’operazione di verifica della firma digitale viene effettuata
ricalcolando, con la medesima funzione di hash usata nella
fase di firma, il valore dell’impronta digitale (hash “fresco”);
poi si decifra con la chiave pubblica del firmatario la firma
(hash firmato) e si controllando che il valore così ottenuto
coincida con hash “fresco”.
Gli algoritmi per la firma digitale più utilizzati sono RSA,
mentre per le funzioni hash abbiamo SHA-1, RIPEMD-160
- 103 -
CAP. 5 - CRITTOGRAFIA
A
CHIAVE PUBBLICA
5.2.1 Algoritmo RSA
Proposto nel 1978 da Rivest, Shamir e Adleman [RSA78],
da cui il nome, è il primo sistema di crittografia a chiavi
pubbliche basato sui concetti proposti da Diffie ed Hellman
ed è anche quello attualmente più diffuso ed utilizzato. Il
metodo si basa sulla fattorizzazione di interi di grandi
dimensioni
e
per
utilizzarlociascun
interlocutore
deve
compiere le seguenti azioni:
Scegliere due grandi interi p e q che siano primi; il loro
prodotto corrisponde al valore di N chiamato modulo, in
quanto utilizzato nel calcolo del modulo nelle operazioni di
codifica e decodifica.
Scegliere un intero e, che sia primo rispetto a T = (p-1)
* (q-1) detta funzione di Eulero, ossia tale che tra T ed e
non ci siano fattori comuni eccetto 1. Si ottiene così la
chiave pubblica di codifica
Kp = (e,N).
Calcolare l’intero d per il quale risulta e * d mod T = 1,
ossia trovare l'intero d per cui (e*d-1) sia divisibile per T. Si
ottiene così la chiave segreta di decodifica Ks = (d,N).
- 104 -
CAP. 5 - CRITTOGRAFIA
A
CHIAVE PUBBLICA
Il messaggio cifrato X corrispondente ad un messaggio M
si ottiene dalla relazione:
X=Me mod N mentre la decodifica avviene secondo la
relazione:
Xd mod N = (Me mod N)d mod N = Med mod N = M.
La sicurezza dello RSA è affidata alla difficoltà di
determinare i fattori primi di un intero quando questo è
molto grande, difficoltà che aumenta in modo esponenziale
al crescere del numero di bit usati per la chiave. Infatti se
un intrusore riuscisse a sapere che N è fattorizzato in p e q,
allora potrebbe calcolare T e
conoscendo d risalire a c tramite l'equazione e*d mod T
= 1.
Va osservato che tale algoritmo può essere utilizzato sia
per cifrare un documento sia per firmarlo digitalmente. Per
far ciò è sufficiente invertire la sequenza di utilizzo delle
chiavi: il mittente firma il documento con la propria chiave
privata e poi il destinatario verifica la tale firma con la
chiave pubblica del
mittente. Ciò è possibile in virtù della seguente proprietà
dell’aritmetica modulare:
(Me mod N)d mod N = (Md mod N)e mod N = Med mod
N = M.
- 105 -
CAP. 5 - CRITTOGRAFIA
A
CHIAVE PUBBLICA
La lunghezza della chiave dipende dal grado di sicurezza
richiesto; tipici valori sono 512, 1024 o 2048 bit.
Esempio:
p=3 e q=11 N=p*q=33
T=(p-1)*(q-1)=20 e=7
e*d mod T = 1
bisogna trovare un q intero tale che
T*x+1 sia un
multiplo di e x=1 d = (T*x+1)/e = 3
chiave privata = (7 , 33) chiave pubblica = (3 , 33)
M = 15 X = (15)^3 mod 33 = 9
(9)^ 7mod 33 = 15 = M
5.2.2 Algoritmo SHA-1
La funzione hash SHA (Secure Hash Algorithm) produce
un digest message di 160 bit per ogni messaggio di
lunghezza inferiore a 2^64 bit. Vediamo le principali fasi
algoritmiche [S96]:
Il messaggio viene completato con dei bit per ottenere
multipli di 512 bit (padding): all'inizio del messaggio si
mette un 1 seguito da tanti zeri quanti sono necessari
affinché il messaggio sia più corto di 64 bit di un multiplo di
- 106 -
CAP. 5 - CRITTOGRAFIA
A
CHIAVE PUBBLICA
512 bit, mentre alla fine del messaggio si mettono 64 bit
che danno la lunghezza del messaggio prima del padding.
Vengono inizializzate 5 variabili di 32 bit l'una (A, B, C,
D, E).
L'algoritmo processa blocchi di 512 bit alla volta; ogni
blocco viene processato attraverso 4 funzioni non lineari,
ognuna applicata 20 volte. Senza entrare nei dettagli
implementativi di queste funzioni che fondamentalmente
eseguono operazioni 18 logiche (and, or, not, xor) e
operazioni di shifting, abbiamo come risultato finale che
ogni blocco di 512 bit processato modifica le cinque variabili
iniziali. Una volta processati tutti i blocchi che costituiscono
il messaggio, concatenando tali variabili otteniamo un hash
a 5 x 32 = 160 bit del messaggio.
Tuttora non esistono attacchi crittografici contro SHA-1;
inoltre, producendo un hash a 160 bit, risulta più robusto
ad attacchi di forza - bruta rispetto a MD4 e MD5 che
producono un message digest di 128 bit.
- 107 -
CAP. 5 - CRITTOGRAFIA
A
CHIAVE PUBBLICA
5.3 CERTIFICATI ELETTRONICI
Nella tecnologia di crittografia a chiave pubblica sia in
fase di cifratura sia in fase di verifica di una firma digitale
occorre ritrovare la chiave pubblica o del destinatario di un
messaggio o del firmatario del messaggio firmato. In
entrambi i casi il valore delle chiavi pubbliche non è
confidenziale; la criticità del reperimento delle chiavi sta nel
garantire non la confidenzialità, ma l’autenticità delle chiave
pubbliche, ossia sta nell’assicurare che una certa chiave
pubblica appartenga effettivamente all’interlocutore per cui
si vuole cifrare o di cui si deve verificare la firma. Se,
infatti, una terza parte prelevasse la chiave pubblica del
destinatario sostituendola con la propria, il contenuto dei
messaggi cifrati sarebbe disvelato e le firme digitali
potrebbero essere falsificate.
La distribuzione delle chiavi pubbliche è, pertanto, il
problema cruciale della tecnologia a chiave pubblica. In un
dominio con un numero limitato di utenti si potrebbe anche
ricorrere ad un meccanismo manuale di distribuzione delle
chiavi: due interlocutori che abbiano una relazione di
conoscenza
già
stabilita,
potrebbero,
ad
esempio,
scambiarsi reciprocamente le chiavi attraverso floppy disk.
Meccanismi di distribuzione manuale diventano, tuttavia,
assolutamente
inadeguati
ed
impraticabili
- 108 -
in
dominio
CAP. 5 - CRITTOGRAFIA
A
CHIAVE PUBBLICA
scalabile dove non c’è alcuna diretta conoscenza prestabilita
tra gli interlocutori.
Il problema della distribuzione delle chiavi pubbliche è
risolto tramite l’impiego dei certificati elettronici. I certificati
a
chiave
pubblica
costituiscono,
infatti,
lo
strumento
affidabile e sicuro attraverso cui rispondere ad esigenze di
scalabilità;
attraverso
i
certificati
elettronici
le
chiavi
pubbliche vengono distribuite e rese note agli utenti finali
con
garanzia
di
autenticità
e
integrità.
L’utilizzo
dei
certificati elettronici presuppone, tuttavia, l’esistenza di una
Autorità di Certificazione (Certification Authority o CA) che
li emetta e li gestisca.
Ogni certificato è una struttura dati costituita da una
parte dati contenente al minimo:
• informazioni che identificano univocamente il possessore
di una chiave pubblica (ad esempio il nome);
• il valore della chiave pubblica;
• il periodo di validità temporale del certificato;
• la firma digitale della autorità di certificazione con cui si
assicura
autenticità
della
chiave
ed
integrità
delle
informazioni contenute nel certificato; La semplicità del
meccanismo
di
distribuzione
delle
chiavi
è
diretta
conseguenza delle caratteristiche stesse dei certificati: i
certificati, infatti, possono essere distribuiti senza dover
necessariamente ricorrere ai tipici servizi di sicurezza di
confidenzialità,
integrità,
e
comunicazioni.
- 109 -
autenticazione
delle
CAP. 5 - CRITTOGRAFIA
A
CHIAVE PUBBLICA
Per le proprietà della crittografia a chiave pubblica non
c'è infatti alcun bisogno di garantire la riservatezza del
valore
della
chiave
pubblica;
durante
il
processo
di
distribuzione, poi, non ci sono requisiti di autenticazione ed
integrità
dal
momento
che
il
certificato
è
per
sua
costituzione una struttura già protetta (la firma digitale
dell'autorità di certificazione sul certificato fornisce, infatti,
sia autenticazione sia integrità).
Se,
quindi,
un
intrusore
tentasse,
durante
la
pubblicazione del certificato, di alterarne il contenuto, la
manomissione sarebbe immediatamente rilevata in fase di
verifica della firma sul certificato; il processo di verifica
fallirebbe e l’utente finale sarebbe
avvertito
della
non
integrità
della
chiave
pubblica
contenuta nel certificato.
Le
caratteristiche
stesse,
quindi,
del
certificato
permettono di distribuire i certificati a chiave pubblica
anche mediante canali non sicuri (file server insicuri o
sistemi
di
directory
o
protocolli
di
comunicazione
intrinsecamente insicuri).
5.3.1 Standard X.509 per i certificati
Lo
standard
ormai
diffusamente
riconosciuto
di
definizione del formato dei certificati è quello descritto nello
standard X.509 ISO/IEC/ITU (Visa e MasterCard hanno ad
- 110 -
CAP. 5 - CRITTOGRAFIA
A
CHIAVE PUBBLICA
esempio adottato le specifiche X.509 come base per la
definizione dello standard per il commercio elettronico SET,
Secure Electronic Transaction).
Tale standard è giunto alla terza versione (X.509v3),
dopo che le precedenti due versioni si erano dimostrate
insufficienti a risolvere certe problematiche. Vediamo da
quali campi è composto un certificato:
• Version: indica la versione del formato del certificato
(1, 2 o 3)
• Serial number: è un codice numerico che identifica il
certificato tra tutti i certificati emessi dall’Autorità di
Certificazione
• Signature Algorithm: specifica l’algoritmo utilizzato
dalla CA per firmare il certificato; è data dalla coppia
funzione hash – algoritmo a chiave pubblica
• Issuer X.500 Name: è il nome della CA; è fornito
secondo lo standard di naming X.500
• Validity Period: specifica la data e l’ora di inizio
validità e di fine validità del certificato
• Subject X.500 Name: nome del possessore del
certificato
• Subject Public Key Information: contiene il valore
della chiave pubblica del possessore del certificato e
l’algoritmo con cui tale chiave viene usata
- 111 -
CAP. 5 - CRITTOGRAFIA
A
CHIAVE PUBBLICA
• Issuer Unique Identifier: è una stringa di bit
aggiuntivi, opzionale, usata nel caso in cui nella
struttura ad albero ci siano due CA
• Subject Unique Identifier: è una stringa di bit
aggiuntivi, opzionale, usata nel caso di omonimia di
due membri in una stessa CA
• CA Signature: è la firma digitale della CA sul
certificato
Nella
aggiunto
questo
versione
un
3,
rispetto alle
ulteriore
campo
è
campo
precedenti,
(standard
suddiviso
in
tre
è
stato
extention);
sottoinsiemi:
l’identificatore del tipo di estensione, un indicatore di
criticità e il valore effettivo dell’estensione; l’indicatore di
criticità
facilita
l’interoperabilità
tra
sistemi
che
non
utilizzano certificati con determinate estensioni e sistemi
che, invece, interpretano tutte le estensioni definite a livello
di standard; l’indicatore di criticità è semplicemente un flag
che stabilisce se l’estensione è critica o non critica; se
l’estensione non è critica, significa che il sistema che deve
elaborare
il
certificato
può
eventualmente
ignorare
l’estensione in questione se non è in grado di interpretarla.
Le estensioni standard definite nei certificati X.509v3 si
suddividono in quattro gruppi:
- 112 -
CAP. 5 - CRITTOGRAFIA
• estensioni
contenenti
informazioni
A
CHIAVE PUBBLICA
sulla
chiave
pubblica che specificano il tipo di utilizzo per cui è
stata emessa una certa chiave.
• estensioni contenenti informazioni aggiuntive relative
all’Autorità di Certificazione e all’utente possessore del
certificato (ad esempio nomi alternativi per la CA e per
l’utente).
• estensioni contenenti informazioni sulle politiche di
emissione e sulle finalità di utilizzo dei certificati (le
estensioni “certificate policy3” e “policy mapping4”).
• estensioni contenenti informazioni sui vincoli di spazio
dei
nomi
o
ritrovamento
di
politica
o
la
da
verifica
imporre
di
un
durante
il
certificato
appartenente ad un dominio di fiducia esterno.
5.3.2 Necessità di coppie di chiavi distinte per
cifratura e firma
L’algoritmo a chiave pubblica più utilizzato, RSA, ha la
proprietà di permettere sia operazioni di cifratura sia
operazioni di firma digitale con la stessa coppia di chiavi
crittografiche; tuttavia un uso doppio della coppia di chiavi
è sconsigliato. I motivi sono deducibili dall’esame dei
requisiti di gestione che sono differenti nel caso in cui le
chiavi siano utilizzate per la cifratura o per la firma digitale.
- 113 -
CAP. 5 - CRITTOGRAFIA
A
CHIAVE PUBBLICA
Per la coppia di chiavi di firma digitale si devono, infatti,
rispettare i seguenti requisiti:
• la chiave privata di firma deve essere custodita
durante l’intero periodo di validità in modo tale che
solo il suo legittimo possessore possa averne accesso;
tale requisito è un presupposto fondamentale per
fornire supporto a servizi di non ripudio (vedremo nel
terzo capitolo come la legge italiana imponga che la
chiave di firma sia custodita all’interno dello stesso
dispositivo in cui sarà utilizzata.)
• una chiave privata di firma non deve essere sottoposta
a backup per proteggersi contro perdite accidentali
della chiave privata; se la chiave di firma, infatti, viene
accidentalmente persa, una nuova coppia di chiavi di
firma
può
sottoporre
essere
a
facilmente
backup
la
generata,
chiave
privata
mentre
di
firma
contrasterebbe con il primo requisito
• una chiave privata di firma non necessita di essere
archiviata; l’archiviazione contrasterebbe con il primo
requisito; una chiave privata di firma deve essere
distrutta in modo sicuro allo scadere della sua validità;
se, infatti, si potesse risalire al suo valore anche dopo
la cessazione del suo utilizzo, tale chiave privata
potrebbe ugualmente essere utilizzata per falsificare la
firma su vecchi documenti (per evitare ciò, si può
ricorrere a servizi di validazione temporale.)
- 114 -
CAP. 5 - CRITTOGRAFIA
A
CHIAVE PUBBLICA
• una chiave pubblica di firma necessita di essere
archiviata; tale chiave potrebbe essere utilizzata per la
verifica di firme apposte su documenti in tempi
successivi alla scadenza della validità della coppia di
chiavi di firma.
Per la coppia di chiavi di cifratura, invece, si devono
rispettare i seguenti requisiti, in contrasto con i precedenti:
• la
chiave
privata,
utilizzata
nelle
operazioni
di
decifratura, necessita di essere sottoposta a backup o
archiviata; infatti, se una chiave privata venisse persa
(ad esempio a causa della corruzione del dispositivo di
protezione della chiave o per dimenticanza da parte
del legittimo possessore del segreto utilizzato per
sbloccare l’accesso al dispositivo di protezione) e non
ci fossero meccanismi di recupero della chiave (key
recovery),
sarebbe
inaccettabile
perdere
irrimediabilmente l’accesso ai dati cifrati con quella
chiave.
• la chiave pubblica utilizzata per la cifratura dei dati
non
necessita
generalmente
di
archiviazione;
l’algoritmo utilizzato determina se un backup della
chiave pubblica è necessario o meno (se si utilizza un
meccanismo di trasporto delle chiavi basato su RSA, il
backup non è necessario, può diventarlo se si utilizza,
- 115 -
CAP. 5 - CRITTOGRAFIA
A
CHIAVE PUBBLICA
invece, l’algoritmo Diffie-Hellmann per lo scambio
delle chiavi).
• la chiave privata non deve essere distrutta allo
scadere
della
sua
validità di
impiego
per
poter
continuare a decifrare in futuro i documenti cifrati col
la corrispondente chiave pubblica.
Alla luce delle considerazioni elencate è evidente, quindi,
che, se si impiegasse un’unica coppia di chiavi sia per la
cifratura sia per la firma, sarebbe impossibile garantire il
soddisfacimento contemporaneo di tutti i requisiti. Inoltre si
tenga presente che:
• le realizzazioni a chiave pubblica utilizzate a supporto
della cifratura sono tipicamente soggette a limiti di
esportazioni molto più restrittivi rispetto a quelli
previsti per la firma digitale
• le chiavi di firma e di cifratura possono avere validità
temporalidifferenti
per
motivi
di
politica
organizzativi/gestionali e di sicurezza.
• non tutti gli algoritmi a chiave pubblica hanno la
proprietà dell’algoritmo RSA di effettuare sia cifratura
sia firma con la stessa coppia di chiavi.
- 116 -
CAP. 5 - CRITTOGRAFIA
A
CHIAVE PUBBLICA
5.4 INFRASTRUTTURA A CHIAVE
PUBBLICA
Le
infrastrutture
a
(PKI)
chiave
pubblica
(Public
Key
Infrastructure) forniscono il supporto necessario affinché la
tecnologia di crittografia a chiave pubblica sia utilizzabile su
larga scala. Le infrastrutture offrono servizi relativi alla
gestione delle chiavi e dei certificati e delle politiche di
sicurezza. Le autorità di certificazione e la problematica di
gestione dei certificati elettronici costituiscono, infatti, il
cuore
delle
infrastrutture
a
chiave
pubblica.
Una
infrastruttura a chiave pubblica introduce il concetto di
third-party trust, ossia di quella situazione che si verifica
quando due generiche entità si fidano implicitamente l’una
dell’altra senza che abbiano precedentemente stabilito una
personale relazione di fiducia. Questo è possibile perché
entrambe le entità condividono una relazione di fiducia con
una terza parte comune.
- 117 -
CAP. 5 - CRITTOGRAFIA
A
CHIAVE PUBBLICA
Fig. 5.3: Third-party trust
Third-party
qualsiasi
trust
è
un
implementazione
requisito
su
larga
fondamentale
scala
che
per
utilizzi
crittografia a chiave pubblica e in una PKI viene realizzata
attraverso l’Autorità di Certificazione.
Vediamo
in
dettaglio
quali
sono
i
componenti
fondamentali di una PKI.
Autorità di Registrazione (RA)
L’accertamento dell’identità dell’utente richiedente un
certificato elettronico, deve precedere l’effettiva emissione
del certificato; è indispensabile procedere a tale verifica
dato che con l’emissione di un certificato elettronico si
rende pubblicamente valida l’associazione tra una certa
chiave pubblica e una certa entità. Una volta attestata la
validità dell’identità dell’utente attraverso una serie di
- 118 -
CAP. 5 - CRITTOGRAFIA
A
CHIAVE PUBBLICA
procedure definite nell’ambito di una precisa politica di
sicurezza (ad esempio, il controllo della carta di identità),
l’autorità di registrazione ha il compito di abilitare l’utente
come appartenente ad uno specifico dominio di fiducia ; la
funzionalità di autorità di registrazione può essere espletata
dall’autorità di certificazione stessa oppure delegata ad
altre entità.
Autorità di Certificazione (CA)
Costituisce il cuore di una PKI; la sua principale funzione
consiste nel creare i certificati elettronici per quegli utenti
precedentemente abilitati nella fase di registrazione al
dominio di fiducia di cui la CA è garante; un’Autorità di
Certificazione non si deve limitare esclusivamente alla
generazione dei certificati, ma deve poterne gestire l’intero
ciclo
di
vita.
Il
ciclo
di
vita
comprende
le
fasi
di
generazione, aggiornamento (nel caso in cui il certificato
stia per perdere validità temporale), sostituzione (nel caso
di scadenza della validità temporale) e revoca nel caso in
cui le condizioni di emissione del certificato non siano più
valide. Un ulteriore compito della CA è stabilire relazioni di
fiducia con altre CA.
Sistema di Directory
Contiene i certificati a chiave pubblica, reperibili dagli
utenti qualora sia necessario, e le liste dei certificati
revocati
(CRL). Tale sistema
costituisce
- 119 -
un elemento
CAP. 5 - CRITTOGRAFIA
A
CHIAVE PUBBLICA
fondamentale per la distribuzione su larga scala delle chiavi
pubbliche utilizzate nella cifratura e nella firma dei dati. Il
sistema di Directory si basa su un particolare protocollo di
comunicazione
LDAP
(Lightweight
Directory
Access
Protocol) che utilizza il TCP/IP.
PKI Database
Oltre alla Directory, di solito, c’è un’altra entità dedicata
alla memorizzazione delle chiavi: è il database gestito
esclusivamente dalla CA nel quale viene fatto un backup
delle chiavi e vengono archiviate le chiavi scadute. Questo
database, a differenza della Directory, è privato ed è
accessibile solo dalla CA.
Utenti finali
Gli utenti finali (end-entity) sono dotati del software in
grado di interagire con la PKI in tutte le fasi in cui sia
richiesta un’interazione tra le applicazioni client e la CA o la
directory
(ad
esempio
un’interazione
fondamentale
interviene nella fase di inizializzazione dell’utente, fase nella
quale vengono creati i relativi certificati di cifratura e di
firma).
- 120 -
CAP. 5 - CRITTOGRAFIA
A
CHIAVE PUBBLICA
Figura 1 Architettura di una PKI.
5.4.1 Requisiti di una PKI
L’implementazione di una infrastruttura a chiave pubblica
deve tener conto di una serie di requisiti progettuali che si
possono sintetizzare nei seguenti:
• scalabilità.
• supporto per applicazioni multiple: a beneficio degli
utenti finali in termini di convenienza, sicurezza ed
economia, una stessa infrastruttura deve garantire il
supporto per molteplici applicazioni (posta elettronica
sicura, applicazioni Web, trasferimento di file sicuro);
pertanto, il modello di gestione della sicurezza deve
essere consistente e uniforme per tutte le applicazioni.
- 121 -
CAP. 5 - CRITTOGRAFIA
A
CHIAVE PUBBLICA
• interoperabilità tra infrastrutture differenti: non è certo
una soluzione praticabile quella di realizzare un’unica
infrastruttura rispondente alle necessità di sicurezza di
un dominio di utenti su scala globale; è, quindi, evidente
che si debba ricorrere a domini di sicurezza distinti,
ognuno
• amministrato da un’infrastruttura specifica. Tuttavia,
l’interoperabilità di tali infrastrutture distinte deve essere
assicurata ed è richiesta per garantire il raggiungimento
di un buon livello di scalabilità.
• supporto per una molteplicità di politiche: cammini di
certificazione considerati appropriati per un’applicazione,
possono non essere considerati altrettanto validi per
un’altra applicazione; è, quindi, necessario implementare
meccanismi che permettano da un lato di attribuire
politiche differenti ai vari cammini di certificazione
dall’altro di associare ad ogni applicazione una politica di
sicurezza specifica.
• conformità agli standard: una vera interoperabilità tra
PKI distinte è ottenibile soltanto con l’adozione di
standard che definiscono i protocolli funzionali e di
comunicazione relativi ai componenti costitutivi di una
infrastruttura a chiave pubblica.
- 122 -
CAP. 5 - CRITTOGRAFIA
A
CHIAVE PUBBLICA
5.5 GESTIONE DEI CERTIFICATI
5.5.1 Ciclo di vita dei certificati
L’emissione effettiva di un certificato elettronico da parte
di un’Autorità di Certificazione a favore di un utente finale
deve
essere
preceduta
da
una
fase
di
registrazione
dell’utente richiedente il certificato elettronico. Attraverso il
processo di registrazione l’utente richiedente un servizio di
certificazione si identifica presso l’autorità preposta al
servizio di registrazione; le credenziali che in questa fase
l’utente
deve
dipendono
sottoporre
fortemente
registrazione
definite
all’Autorità
dalle
modalità
nell’ambito
di
di
Registrazione
e
procedure
una
politica
di
di
sicurezza.
Il processo di registrazione stabilisce una relazione
iniziale tra utente finale ed Autorità di Certificazione;
l’utente finale, una volta attestata l’autenticità della sua
identità, viene registrato nel dominio di fiducia gestito dalla
CA. L’obiettivo, di primaria importanza del processo di
registrazione è, quindi, quello di garantire che la chiave
pubblica,
di
certificazione,
cui
un
certo
appartenga
utente
finale
effettivamente
richiedente.
- 123 -
al
richiede
nome
la
del
CAP. 5 - CRITTOGRAFIA
A
CHIAVE PUBBLICA
Terminata la fase di registrazione, l’utente può richiedere
l’emissione di un certificato elettronico. La procedura di
generazione
di
un
certificato
elettronico
consiste
dei
seguenti passi:
• l’utente finale sottopone all’autorità di certificazione le
informazioni da certificare.
• l’Autorità di
Certificazione può verificare l’accuratezza
delle informazioni presentate in accordo a politiche e
standard applicabili.
• l’Autorità
di
Certificazione
firma
le
informazioni
generando il certificato e lo pubblica sul sistema di
Directory; di solito, la CA archivia una copia del
certificato sul suo database privato; ogni operazione di
generazione di certificati elettronici viene registrata su un
archivio di registrazione dati.
Ogni certificato elettronico generato ha una validità
temporale limitata al cui termine va sostituito; il periodo di
validità di un certificato, in assenza di compromissioni o usi
illeciti, garantisce l’utente che deve utilizzare tale certificato
che la chiave pubblica possa essere utilizzata per lo scopo
per cui è stata generata e che l’associazione tra la chiave
pubblica e le altre informazioni contenute nel certificato sia
ancora valida.
- 124 -
CAP. 5 - CRITTOGRAFIA
A
CHIAVE PUBBLICA
5.5.2 La gestione delle chiavi
Alla gestione del ciclo di vita dei certificati è strettamente
collegata
la
gestione
delle
coppie
di
chiavi
(key
management); tale gestione comprende le funzioni di
generazione, di backup, recupero ed aggiornamento delle
chiavi.
In generale, le chiavi sono generate dagli stessi utenti
finali
che
ne
hanno
bisogno
(key
generation);
successivamente, gli utenti possono chiedere alla CA la
certificazione di tali chiavi. La generazione e la successiva
certificazione
costituiscono
la
fase
di
inizializzazione
dell’utente.
La necessità di mantenere copie delle chiavi (key
backup) nasce dal fatto che l’eventuale perdita delle chiavi
comporta l’impossibilità di decifrare i messaggi cifrati e di
verificare i messaggi firmati. Spesso le organizzazioni
richiedono un backup delle chiavi dei loro membri per
evitare
che
l’onere
di
mantenimento
delle
copie
sia
esclusivamente di questi ultimi. Tali organizzazioni possono
avere la necessità di verificare documenti digitalmente
firmati da loro membri anche oltre la validità temporale di
tali chiavi e non possono fidarsi unicamente alle eventuali
copie di backup fatte dal possessore della chiave.
Inoltre c’è sempre la possibilità che un utente si
dimentichi la password di protezione delle sue chiavi;
- 125 -
CAP. 5 - CRITTOGRAFIA
A
CHIAVE PUBBLICA
pertanto deve essere possibile recuperare le proprie chiavi
e di impostare una nuova password (key recovery).
Un
altro
problema
nella
gestione
delle
chiavi
è
l’aggiornamento (key update). Spesso le organizzazioni
impongono ai loro membri un aggiornamento a intervalli
regolari delle loro chiavi. Questo può comportare una gran
mole di lavoro, in particolar modo per organizzazione con
un gran numero di partecipanti. Infatti, l’aggiornamento
delle
chiavi
comporta
una
riemissione
del
certificato
elettronico corrispondente. A questo si aggiunga il fatto
che,
non
raramente,
capita
che
le
chiavi
dell’intera
organizzazione scadono lo stesso giorno.
5.5.3 La revoca di un certificato
L’operazione di revoca di un certificato costituisce una
fase della gestione del ciclo di vita dei certificati di alta
criticità. Il certificato elettronico deve essere revocato in
presenza delle seguenti condizioni:
- compromissione rilevata o semplicemente sospettata
della chiave privata corrispondente alla chiave pubblica
contenuta nel certificato.
- cambiamento
di
una
qualsiasi
delle
informazioni
contenute nel certificato elettronico o delle condizioni
iniziali di registrazione.
- 126 -
CAP. 5 - CRITTOGRAFIA
La
revoca
del
certificato
A
elettronico
CHIAVE PUBBLICA
è
effettuata
dall’Autorità di Certificazione e generalmente viene avviata
su richiesta dello stesso utente finale; in questo caso, data
la criticità e le implicazioni dell’operazione di revoca, è
indispensabile predisporre, un sistema di autenticazione
della richiesta di revoca.
La difficoltà legata al processo di revoca sta nel garantire
una corretta notifica su larga scala dell’avvenuta revoca di
un particolare certificato; ogniqualvolta un utente finale
intende utilizzare un certificato o per cifrare dati o per
verificare una firma, deve essere informato sullo stato di
quel certificato.
Il meccanismo più comunemente utilizzato per la notifica
su larga scala di avvenute revoche fa uso delle cosiddette
liste di revoca dei certificati (Certificate Revocation List o
CRL); la gestione di tali liste è delegata alla CA; nell’ambito
del dominio amministrato, ogni CA pubblica periodicamente
una
struttura
dati
contenente
l’elenco
dei
certificati
revocati, ossia una lista, firmata digitalmente dall’Autorità
di Certificazione, che riporta i certificati revocati, la data
temporale in cui è avvenuta la revoca ed eventualmente il
motivo della revoca; i motivi per cui anche la CRL deve
essere firmata digitalmente sono analoghi a quelli descritti
nel caso dei certificati elettronici.
La CRL, al pari dei certificati, deve essere pubblicata in
modo
che
sia
consultabile
da
qualunque
utente.
La
frequenza di pubblicazione di una CRL dipende fortemente
- 127 -
CAP. 5 - CRITTOGRAFIA
dalla
politica
di
dell’organizzazione;
sicurezza
una
A
CHIAVE PUBBLICA
definita
determinata
all’interno
politica
potrebbe
richiedere la pubblicazione di una nuova CRL ogniqualvolta
si
richiede
tuttavia,
una
molto
revoca;
tale
dispendiosa
procedura
dal
risulterebbe,
punto
di
vista
amministrativo.
Generalmente, la CA rilascia liste di revoca dei certificati
su base periodica, con intervalli di periodicità definibili a
livello di politica di sicurezza.
Le liste di revoca giocano un ruolo di fondamentale
importanza in tutti i processi crittografici, in quanto devono
essere consultate sia in fase di cifratura sia in fase di
verifica di una firma.
Infatti, prima di cifrare un messaggio, va verificato che la
chiave
pubblica
che
si
deve
usare
per
la
cifratura
appartenga ad un certificato valido. Analogo discorso vale
per la verifica della firma, poiché una firma può essere
ritenuta valida solo se il certificato del firmatario, oltre ad
essere autentico e integro, non è stato revocato.
La dimensione di una CRL è di fondamentale importanza
nelle prestazioni di una PKI. Per ovviare ad un possibile
overhead dovuto alle eccessive dimensione della lista di
revoca sono stati introdotti i cosiddetti punti di distribuzione
delle CRL che consentono di partizionare in modo arbitrario
l’intera CRL: ogni partizione è associata ad un punto di
distribuzione. In questo modo la massima dimensione che
- 128 -
CAP. 5 - CRITTOGRAFIA
può
raggiungere
una
singola
partizione
A
CHIAVE PUBBLICA
è
controllata
dall’Autorità di Certificazione.
Il
metodo
di
distribuzione
della
notifica
di
revoca
attraverso CRL distribuite periodicamente dalla CA è detto
di tipo pull; il nome del metodo deriva dal fatto che, quando
necessario, sono i sistemi degli utenti finali a reperire le
CRL da un sistema di distribuzione.
Il problema, tuttavia, legato al metodo di distribuzione
delle notifiche delle revoche tramite CRL, è quello della
latenza introdotta. Esistono transazioni in cui è necessario
garantire revoca in tempo reale e che non possono tollerare
finestre temporali in cui le CRL non sono perfettamente
allineate; il metodo sopra descritto presenta proprio la
limitazione che la latenza introdotte nelle notifiche delle
revoche dipende dalla periodicità di emissione delle CRL.
Una possibile soluzione potrebbe essere l’emissione
forzata di una CRL fuori dalla sequenza degli intervalli
temporali prestabilita da parte della CA; ma se viene
avviato
un
attacco
attivo
finalizzato
ad
impedire
la
pubblicazione di tale lista di revoca fuori sequenza, non c’è
un meccanismo affidabile di distribuzione delle CRL che
permetta di rilevare con assoluta certezza la mancata
pubblicazione di tale CRL.
Esistono metodi alternativi di distribuzione delle CRL
mirati a risolvere il problema della revoca in tempo reale.
Un primo approccio è quello che utilizza un metodo di tipo
push in cui è l’Autorità di Certificazione ad inviare in
- 129 -
CAP. 5 - CRITTOGRAFIA
A
CHIAVE PUBBLICA
modalità “broadcast” le CRL non appena sopravviene una
nuova revoca. Se, da un lato, questo metodo garantisce
tempi di distribuzione delle CRL estremamente veloci,
tuttavia, dall’altro lato presenta alcuni svantaggi che lo
rendono non diffusamente impiegato. Innanzitutto tale
metodo richiede una modalità di distribuzione sicura che
garantisca che le CRL effettivamente raggiungano i sistemi
degli utenti finali previsti; in secondo luogo, esso può dar
luogo ad un incremento considerevole di traffico sulla rete;
in terzo luogo tale metodo non presenta né uno standard,
né
una
proposta
di
definizione
che
ne
permetta
un’implementazione diffusa.
Un altro metodo di notifica delle revoche, alternativo a
quelli precedenti, consiste nell’effettuare una transazione
online di verifica dello stato del certificato (tale protocollo,
definito a livello di Internet draft, è conosciuto con il nome
di OCSP, “Online Certificate Status Protocol”); il sistema
PKI mette a disposizione un server online dedicato a questo
servizio
che
garantisca
disponibilità
ed
accessibilità
continua del servizio.
5.5.4 I cammini di certificazione
Se
si
potesse
Certificazione
su
disporre
scala
di
globale,
un’unica
il
Autorità
problema
di
della
distribuzione, del reperimento e della verifica della validità
- 130 -
CAP. 5 - CRITTOGRAFIA
A
CHIAVE PUBBLICA
delle chiavi pubbliche non sussisterebbe; tuttavia una tale
soluzione
non
è
praticabile
per
motivi
di
scalabilità,
flessibilità e sicurezza. Diventa, quindi, inevitabile ricorrere
ad un modello costituito da Autorità di Certificazione
multiple tra loro concatenate secondo differenti modelli
organizzativi, detti anche modelli di fiducia.
In uno scenario costituito da una molteplicità di Autorità
di Certificazione su larga scala, strutturate secondo un
certo modello organizzativo, non è pensabile che ogni
utente abbia diretta conoscenza delle chiavi pubbliche di
ogni potenziale interlocutore, sotto forma di certificato
elettronico, o delle chiavi pubbliche delle corrispondenti
autorità
di
certificazione
competenti.
Occorre,
quindi,
disporre di un meccanismo corretto di ritrovamento dei
certificati
elettronici
degli
interlocutori
appartenenti
a
domini di sicurezza esterni. Il modello generale su cui si
basano tutti i sistemi di distribuzione su larga scala delle
chiavi pubbliche sotto forma di certificati elettronici, utilizza
le cosiddette catene di certificazione, altrimenti conosciute
come cammini di certificazione.
Il
problema
del
ritrovamento
di
un
cammino
di
certificazione consiste sostanzialmente nel trovare, se
esiste, un cammino di certificazione che permetta di
verificare l’autenticità del certificato elettronico di uno
specifico utente remoto a partire da un insieme di chiavi
pubbliche, assunte come radici del cammino, di cui si ha
diretta e sicura conoscenza; la risoluzione del problema,
- 131 -
CAP. 5 - CRITTOGRAFIA
A
CHIAVE PUBBLICA
quindi, assume per date certe condizioni iniziali: tali
condizioni iniziali si identificano nelle chiavi di specifiche
autorità di certificazione.
- 132 -
CAP. 6 - CONCLUSIONI
CONCLUSIONI
Lo scopo del progetto, era quello di creare una struttura
software flessibile che offrisse servizi di teleconsulto e
teleassistenza distinguendo in modo inequivocabile la fase
di effettuazione dell’ esame dalla fase di refertazione.
Il mio compito era quello di progettare le applicazioni dal
lato client, ossia dal lato del laboratorio e dal lato del
medico, che rispettassero i canoni di sicurezza nello
scambio delle informazioni sensibili; altro punto focale erà
quello di creare interfacce user-friendly per i client in modo
da rendere semplice l’utilizzo delle stesse.
Tutto ciò è stato conseguito attraverso l’impiego delle
tecnologie precedentemente descritte e con la gentile
collaborazione
dell’ASUR
Marche
zona
7
per
quanto
concerne la parte medico informativa.
In prospettiva futura con l’ avvento del documento di
identità elettronico è auspicabile, che i servizi che ora sono
disponibili solo a livello di personale medico o paramedico,
vengano messi a disposizione direttamente per l’ utente
finale : il cittadino.
Il prossimo passo sarà sfruttare la grande flessibilità con
cui è stato progettato MiRo , espandendo le sue funzionalità
in modo da rendere il servizio sanitario efficiente e
capillare.
- 133 -
CAP. 6 - CONCLUSIONI
Il progetto MiRo è stato presentato alla 2nd Conferenza
Internazionale EMMIT 2006:
EURO-MEDITERRANEAN
MEDICAL
INFORMATICS
TELEMEDICINE.
MiRo:
A Virtual Private Network For
Telehealth
Telehealth Services
ROBERTO DI ROSA, MIRCO STURARI,
ALDO FRANCO DRAGONI*, GIUSEPPE GIAMPIERI**
*DEIT, Dipartimento di Elettronica Intelligenza Artificiale e
Telecomunicazioni – Università Politecnica delle Marche,
Ancona
**ASUR Zona 7, Azienda Sanitaria Locale delle Marche Ancona
1
MiRo Project
•
CONTEXT
software-design to organize telemedicine services
•
MOTIVATIONS
necessity to integrate sanitary services in a wide and
delocalized environment
•
SCOPE
to provide a flexible architecture for teleconsulting and
telereporting
2
- 134 -
and
CAP. 6 - CONCLUSIONI
Telemedicine
represents the erogation of sanitary service at distances
through informatics and telecommunications technologies
3
Telemedicine
ensures high quality digital information even for complex
health services
4
- 135 -
CAP. 6 - CONCLUSIONI
Telemedicine
reaches better results if coordinated with the other
applications
5
MiRo - Architecture
is configured as a substrate to integrate sanitary systems
6
- 136 -
CAP. 6 - CONCLUSIONI
MiRo - Finalities
• provides a flexible software framework for
teleconsulting and services development
• integrates with the existing health information
system to facilitate and rationalize information
interchange
• improves and facilitates TCP/IP-based
teleconsulting services in Intra/Internet environment
• provides a report and “second opinion” service
7
Abstract Data-Structure
Data
Data-Structure
• Exam-data: generic digital data produced by an examination
• Report: text-file and digital signature
• Event: database record containing
– the date-time of the insertion in the database
– the examination type
– the laboratory who produced it
- 137 -
8
CAP. 6 - CONCLUSIONI
MiRo - Architecture
DATA-STRUCTURE
• Data: digital data produced
by an examination
• Event: database record that
links to the exam
SYSTEM-ENTITIES
• Repository: archives event
• Laboratory: generates event
• Phisician: reports examination
• Report: text-file containing
report
9
Repository
• Allows laboratories to generate and manage events
• Allows phisicians to control and report examination
• Stores reports allowing teleconsultation
¾Acts as a sophisticated DBMS for event-records
10
- 138 -
CAP. 6 - CONCLUSIONI
Laboratory
• Generates clinical event
• Provides digital data of examination
• Monitors the workflow of reporting phase
• Terminates reporting phase
11
Phisician
• Consults published examination
• Consults reports written by other phisicians
• Compiles and signs report
• Send this report to a timestamp service and then to the
repository
12
- 139 -
CAP. 6 - CONCLUSIONI
From Exam to Report
1. Laboratory executes an examination that
produces digital data
2. Laboratory pubblicates exam through the
creation of an event
3. Phisician compiles and signs a report and
sends it to the timestamp service
4. Timestamp service appends a certificated
datetime to the report and forwards this back
to the phisician
5. Phisician sends this composite-data to the
Repository
6. The Laboratory decides when to terminate the
refertation process
13
Event-Generation Process
Event
Event-Generation
1. Laboratory executes an examination that produces
digital data
2. Laboratory pubblicates exam through the creation of an
event
- 140 -
14
CAP. 6 - CONCLUSIONI
Event-Generation Process
Event
Event-Generation
3. Repository records event informations about exam
4. The exam is reachable through the MiRo Network from
each authorized client
15
Report-Generation Process
Report
Report-Generation
1. Phisician, as client, connects to Repository and can see a
list of events
2. Phisician chooses an event and retrieves linked
examination data
16
- 141 -
CAP. 6 - CONCLUSIONI
Report-Generation Process
Report
Report-Generation
3. Phisician sees reports written by other associates
4. Phisician compiles a report and sends it to the
Repository
17
MiRo - Technologies
• Service-Oriented Architecture based on common
standards widely applied in different sanitary contexts
• implemented through Web Services (SOAP, XML, …),
which are becoming a standard to distribute services
inside an heterogeneous environment such as Internet
• Client can enter in any moment to consult and to insert
event or report data using a common Web Browser
• transactions are encrypted through standard SSL
X509.v3, using standard Digital Certificates
18
- 142 -
CAP. 6 - CONCLUSIONI
MiRo – Development Environment
• Java 2 Platform Standard Edition
• development tools:
– Eclipse 3.1 – as development environment
– Apache Axis and Java Servlet – to realize web services
– Apache Struts and Java Sever Pages – to design web
interfaces
• Java web services technology
– JDBC interface (in our case MySQL).
• Clients adopt just Web Browsers
19
MiRo - Security Layer
• Secure Socket Layer(SSL)
– Confidentiality achieved through cryptography,
guarantees that data can exclusively be read from the
authorized user.
• Digital Sign
– Integrity and no-repudiation, achieved through the
digital sign, guarantees that information are not modified
during the transmission and that those who use the
system assume the responsibilities of what they are doing.
– Authentication achieved through digital certificate,
Username and Password, guarantees that the user is
exactly the person he declares to be.
20
- 143 -
CAP. 6 - CONCLUSIONI
Conclusions and future works
• MiRo is a software architecture for TCP/IP-based
telereporting activities and “second opinion” services
• thanks to its flexibility, can be exploited in many
different operational realities and is able to incorporate
different Intra/Internet-based services.
• In future perspective, we foresee the possibility to
implement and to provide new services and to reach
citizens.
21
Greetings
• ALDO FRANCO DRAGONI
DEIT, Dipartimento di Elettronica Intelligenza Artificiale e
Telecomunicazioni – Università Politecnica delle Marche,
Ancona
• GIUSEPPE GIAMPIERI
ASUR Zona 7, Azienda Sanitaria Locale delle Marche Ancona
THANK FOR YOUR ATTENTION
22
- 144 -
CAP. 6 - CONCLUSIONI
Si ringrazia per la gentile collaborazione e per la pazienza
espressa : tutto il personale dell’ASUR Marche zona 7, Fabio
Tonucci,
Giuseppe
Giampieri,
Sergio
Piersantelli,
Ebe
Tartufo.
Un ringraziamento speciale al prof. Aldo Franco Dragoni per
il sostegno, l’appoggio e per la collaborazione fornita nello
sviluppo dell’intero progetto.
Una dedica particolare a tutte le persone che mi sono state
vicine in questi anni: al mio amico e collega Mirco, tutti gli
amici in particolare : Carlo, Federico, Giorgio, Luca,
Stefano, Mauro, Paolo, Pietro, Cristian, Daniele, Francesco,
Simone, Matteo…. La mia fidanzata, i parenti, mia madre
Nera e in modo particolare mio padre Bruno.
Roberto Di Rosa
- 145 -
APPENDICE - CODICE SORGENTE
APPENDICE
CODICE SORGENTE
Codice
Java
scritto
per
l’implementazione
dell’applicazione Web del lato client.
A.1 Client Application
A.1.1 EventCloseAction.java
A.1.2 EventCloseBean.java
A.1.3 EventItem.java
A.1.4 EventList.java
A.1.5 EventListAction.java
A.1.6 EventListBean.java
A.1.7 EventOpenAction.java
A.1.8 EventOpenBean.java
A.1.9 EventViewAction.java
A.1.10 EventViewBean.java
A.1.11 ReportItem.java
A.1.12 ReportList.java
A.1.13 ReportUploadAction.java
A.1.14 ReportUploadBean.java
A.1.15 ReportViewAction.java
A.1.16 ReportViewBean.java
- 146 -
APPENDICE - CODICE SORGENTE
A.2 Web Service Client
A.2.1 WSLaboratory.java
A.2.2 WSLaboratoryService.java
A.2.3 WSLaboratoryServiceLocator.java
A.2.4 WSLaboratorySoapBindingStub.java
A.2.5 WSRepository.java
A.2.6 WSRepositoryService.java
A.2.7 WSRepositoryServiceLocator.java
A.2.8 WSRepositorySoapBindingStub.java
A.3 Common Library
A.3.1 Certificate.java
A.3.2 Client.java
A.3.3 DataTime.java
A.3.4 FileUtil.java
- 147 -
APPENDICE - CODICE SORGENTE
A.1 CLIENT APPLICATION
A.1.1 EventCloseAction.java
package it.jtelemed.events;
import javax.servlet.http.*;
import org.apache.struts.action.*;
public class EventCloseAction extends
org.apache.struts.action.Action {
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception
{
EventCloseBean closeform = (EventCloseBean)form;
if (closeform.closeEvent()) {
return mapping.findForward("success");
}
else {
return mapping.findForward("failure");
}
}
}
A.1.2 EventCloseBean.java
package it.jtelemed.events;
import it.jtelemed.services.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.rmi.RemoteException;
import org.apache.axis.AxisFault;
import org.apache.axis.client.Service;
- 148 -
APPENDICE - CODICE SORGENTE
public class EventCloseBean extends
org.apache.struts.action.ActionForm {
public static final long serialVersionUID = 1;
private int rep_id = 0;
public EventCloseBean()
{
rep_id = 0;
}
public void setRep_id(int value) {
rep_id = value;
}
public int getRep_id() {
return rep_id;
}
/**
* chiude un evento
*
* @param String rep_id
*
* @return vero se l'evento è stato scaricato chiuso
*/
public boolean closeEvent() {
boolean ret = false;
try {
WSRepositorySoapBindingStub ws_client = new
WSRepositorySoapBindingStub(new URL(new
WSRepositoryServiceLocator().getWSRepositoryAddress()), new
Service());
// Leggo l'allegato, se presente
ret = ws_client.closeevent(rep_id);
} catch (AxisFault ex) {
ret = false;
} catch (MalformedURLException ex) {
ret = false;
} catch (RemoteException ex) {
ret = false;
}
return ret;
}
}
- 149 -
APPENDICE - CODICE SORGENTE
A.1.3 EventItem.java
package it.jtelemed.events;
public class EventItem {
public static final long serialVersionUID = 1;
private
private
private
private
private
private
int rep_id = 0;
String rep_dataevento = "";
String rep_utente = "";
String rep_token = "";
String rep_wslink = "";
String rep_stato = "";
private String rep_codicetarif = "";
private String rep_descrtarif = "";
private String rep_resourcelink = "";
private String rep_descrstato = "";
private String rep_iconfile = "";
public EventItem() {
rep_id = 0;
rep_dataevento = "";
rep_utente = "";
rep_token = "";
rep_wslink = "";
rep_stato = "";
rep_codicetarif = "";
rep_descrtarif = "";
rep_resourcelink = "";
rep_descrstato = "";
rep_iconfile = "";
}
public EventItem(int rep_id, String rep_dataevento,
String rep_utente, String rep_token, String rep_wslink,
String rep_stato, String rep_codicetarif, String
rep_descrtarif) {
this.rep_id = rep_id;
this.rep_dataevento = rep_dataevento;
this.rep_utente = rep_utente;
- 150 -
APPENDICE - CODICE SORGENTE
this.rep_token = rep_token;
this.rep_wslink = rep_wslink;
this.rep_stato = rep_stato;
this.rep_codicetarif = rep_codicetarif;
this.rep_descrtarif = rep_descrtarif;
this.rep_resourcelink = rep_wslink +
"?method=getfile&token=" + rep_token;
switch (Integer.parseInt(rep_stato)) {
case 0:
this.rep_descrstato = "Aperto";
this.rep_iconfile = "icn_eventopenG.png";
break;
case 1:
this.rep_descrstato = "Refertato";
this.rep_iconfile = "icn_eventrefG.png";
break;
default:
this.rep_descrstato = "Chiuso";
this.rep_iconfile = "icn_eventcloseG.png";
break;
}
}
public void setRep_id(int value) {
rep_id = value;
}
public int getRep_id() {
return rep_id;
}
public void setRep_dataevento(String value) {
rep_dataevento = value;
}
public String getRep_dataevento() {
return rep_dataevento;
}
public void setRep_utente(String value) {
rep_utente = value;
}
public String getRep_utente() {
return rep_utente;
}
public void setRep_token(String value) {
- 151 -
APPENDICE - CODICE SORGENTE
rep_token = value;
}
public String getRep_token() {
return rep_token;
}
public void setRep_wslink(String value) {
rep_wslink = value;
}
public String getRep_wslink() {
return rep_wslink;
}
public void setRep_stato(String value) {
rep_stato = value;
}
public String getRep_stato() {
return rep_stato;
}
public void setRep_codicetarif(String value) {
rep_codicetarif = value;
}
public String getRep_codicetarif() {
return rep_codicetarif;
}
public void setRep_descrtarif(String value) {
rep_descrtarif = value;
}
public String getRep_descrtarif() {
return rep_descrtarif;
}
public void setRep_resourcelink(String value) {
rep_resourcelink = value;
}
public String getRep_resourcelink() {
return rep_resourcelink;
}
public void setRep_descrstato(String value) {
rep_descrstato = value;
}
- 152 -
APPENDICE - CODICE SORGENTE
public String getRep_descrstato() {
return rep_descrstato;
}
public void setRep_iconfile(String value) {
rep_iconfile = value;
}
public String getRep_iconfile() {
return rep_iconfile;
}
}
A.1.4 EventList.java
package it.jtelemed.events;
import java.util.*;
public class EventList implements java.util.Collection {
private ArrayList list = new ArrayList();
public int size() {
return list.size();
}
public boolean isEmpty() {
return list.isEmpty();
}
public boolean contains(Object arg0) {
return list.contains(arg0);
}
public Iterator iterator() {
return list.iterator();
}
public Object[] toArray() {
return list.toArray();
}
public Object[] toArray(Object[] arg0) {
return list.toArray(arg0);
- 153 -
APPENDICE - CODICE SORGENTE
}
public boolean add(Object arg0) {
return list.add(arg0);
}
public boolean remove(Object arg0) {
return list.remove(arg0);
}
public boolean containsAll(Collection arg0) {
return list.containsAll(arg0);
}
public boolean addAll(Collection arg0) {
return list.addAll(arg0);
}
public boolean removeAll(Collection arg0) {
return list.removeAll(arg0);
}
public boolean retainAll(Collection arg0) {
return list.retainAll(arg0);
}
public void clear() {
list.clear();
}
}
A.1.5 EventListAction.java
package it.jtelemed.events;
import it.jtelemed.common.*;
import javax.servlet.http.*;
import org.apache.struts.action.*;
public class EventListAction extends
org.apache.struts.action.Action {
public ActionForward execute(ActionMapping mapping,
ActionForm form,
- 154 -
APPENDICE - CODICE SORGENTE
HttpServletRequest request,
HttpServletResponse response)
throws Exception
{
EventListBean bean = (EventListBean)form;
Client cli = Client.create(request.getSession());
bean.setClient(cli);
if (bean.populate()) {
request.setAttribute("eventListBean", bean);
return mapping.findForward("success");
}
else
return mapping.findForward("listevents");
}
}
A.1.6 EventListBean.java
package it.jtelemed.events;
import it.jtelemed.common.Client;
import it.jtelemed.services.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.rmi.RemoteException;
import org.apache.axis.AxisFault;
import org.apache.axis.client.Service;
public class EventListBean extends
org.apache.struts.action.ActionForm {
public static final long serialVersionUID = 1;
private EventList list = null;
public EventListBean()
{
list = new EventList();
}
public EventList getList()
- 155 -
{
APPENDICE - CODICE SORGENTE
return list;
}
public void setList(EventList lst) {
list = lst;
}
private Client client = null;
public void setClient(Client value) {
client = value;
}
public boolean populate() {
boolean populated = false;
try {
String rep_list = "";
EventItem eventItem;
//System.setProperty("javax.net.ssl.trustStore","C:/Pr
ogram Files/Java/jre1.5.0_05/lib/security/cacerts");
//System.setProperty("javax.net.ssl.trustStorePassword
","changeit");
WSRepositorySoapBindingStub ws_client = new
WSRepositorySoapBindingStub(new URL(new
WSRepositoryServiceLocator().getWSRepositoryAddress()), new
Service());
rep_list =
ws_client.listevents(client.user_id);
if (rep_list != null && rep_list.length() >
0) {
String[] rep_events =
rep_list.split("§");
String[] rep_event;
if (rep_events != null &&
rep_events.length > 0) {
for (int i = 0; i <
rep_events.length; ++i)
{
rep_event =
rep_events[i].split(";");
if (rep_event != null &&
rep_event.length == 8) {
eventItem = new
EventItem(new Integer(rep_event[0]).intValue(),
- 156 -
APPENDICE - CODICE SORGENTE
rep_event[1], rep_event[2], rep_event[3], rep_event[4],
rep_event[5], rep_event[6], rep_event[7]);
list.add(eventItem);
}
}
}
}
populated = true;
} catch (AxisFault ex) {
populated = false;
} catch (MalformedURLException ex) {
populated = false;
} catch (RemoteException ex) {
populated = false;
}
return populated;
}
}
A.1.7 EventOpenAction.java
package it.jtelemed.events;
import it.jtelemed.common.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import
import
import
import
import
org.apache.struts.action.ActionForm;
org.apache.struts.action.ActionForward;
org.apache.struts.action.ActionMapping;
org.apache.struts.action.ActionMessage;
org.apache.struts.action.ActionMessages;
import org.apache.struts.action.*;
public class EventOpenAction extends Action {
private Client client = null;
public void setClient(Client value) {
client = value;
}
- 157 -
APPENDICE - CODICE SORGENTE
public EventOpenAction() {
}
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception
{
// create a new EventInsertBean with form data
EventOpenBean bean = (EventOpenBean)form;
// Parametri che vengono caricati
bean.setEvt_token(FileUtil.extractFileName(bean.getEvt
_filename()));
bean.setEvt_wslink(client.user_labwslink);
//bean.setEvt_wslink(this.getServlet().getServletConte
xt().getInitParameter("wsLink"));
// check to see if this user/password combination
are valid
if(bean.validateEvent())
{
request.setAttribute("evt_trf_codice",bean.getEvt_trf_
codice());
request.setAttribute("evt_esterno",bean.getEvt_esterno
());
request.setAttribute("evt_token",bean.getEvt_token());
request.setAttribute("evt_wslink",bean.getEvt_wslink()
);
request.setAttribute("evt_richiedente",bean.getEvt_ric
hiedente());
request.setAttribute("evt_impegnativa",bean.getEvt_imp
egnativa());
request.setAttribute("evt_note",bean.getEvt_note());
request.setAttribute("evt_filename",bean.getEvt_filena
me());
//return (mapping.findForward("success"));
- 158 -
APPENDICE - CODICE SORGENTE
if(bean.insertEvent())
{
return
(mapping.findForward("success"));
}
else
{
// create ActionMessage and save in the
request
ActionMessages errors = new
ActionMessages();
ActionMessage error = new
ActionMessage("error.openevent.invalid");
errors.add("openevent",error);
this.saveErrors(request, errors);
return
(mapping.findForward("failure"));
}
}
else // data not validated
{
if (!bean.isEmpty()) {
// create ActionMessage and save in the
request
ActionMessages errors = new
ActionMessages();
ActionMessage error = new
ActionMessage("error.openevent.invalid");
errors.add("openevent",error);
this.saveErrors(request, errors);
}
return (mapping.findForward("failure"));
}
}
}
A.1.8 EventOpenBean.java
package it.jtelemed.events;
import it.jtelemed.common.*;
import it.jtelemed.services.*;
- 159 -
APPENDICE - CODICE SORGENTE
import java.net.MalformedURLException;
import java.net.URL;
import java.rmi.RemoteException;
import javax.servlet.http.HttpServletRequest;
import
import
import
import
import
org.apache.axis.AxisFault;
org.apache.axis.client.Service;
org.apache.struts.action.ActionErrors;
org.apache.struts.action.ActionMapping;
org.apache.struts.action.ActionMessage;
public class EventOpenBean extends
org.apache.struts.action.ActionForm {
public static final long serialVersionUID = 1;
private
private
private
private
private
private
private
private
private
int evt_id = -1;
String evt_trf_codice = "";
Boolean evt_esterno = new Boolean(false);
String evt_token = "";
String evt_wslink = "";
String evt_richiedente = "";
String evt_impegnativa = "";
String evt_note = "";
String evt_filename = "";
private String subjectCN = "";
public EventOpenBean()
{
// Richiamo il metodo di reset che mi inizializza i
valori
reset(null, null);
}
public void reset(ActionMapping actionMapping,
HttpServletRequest request) {
evt_trf_codice = "";
evt_esterno = new Boolean(false);
evt_token = "";
evt_wslink = "";
evt_richiedente = "";
evt_impegnativa = "";
evt_note = "";
evt_filename = "";
if (client != null)
subjectCN = client.user_name;
else
- 160 -
APPENDICE - CODICE SORGENTE
subjectCN = "";
}
public ActionErrors validate(ActionMapping
actionMapping, HttpServletRequest request) {
ActionErrors errors = new ActionErrors();
if((evt_trf_codice == null) ||
(evt_trf_codice.length() < 1))
errors.add("evt_trf_codice", new
ActionMessage("error.trf_codice.required"));
return errors;
}
public String getEvt_trf_codice() {
return evt_trf_codice;
}
public Boolean getEvt_esterno() {
return evt_esterno;
}
public String getEvt_token() {
return evt_token;
}
public String getEvt_wslink() {
return evt_wslink;
}
public String getEvt_richiedente() {
return evt_richiedente;
}
public String getEvt_impegnativa() {
return evt_impegnativa;
}
public String getEvt_note() {
return evt_note;
}
public String getEvt_filename() {
return evt_filename;
}
public void setEvt_trf_codice(String string) {
evt_trf_codice = string;
}
- 161 -
APPENDICE - CODICE SORGENTE
public void setEvt_esterno(Boolean bool) {
evt_esterno = bool;
}
public void setEvt_token(String string) {
evt_token = string;
}
public void setEvt_wslink(String string) {
evt_wslink = string;
}
public void setEvt_richiedente(String string) {
evt_richiedente = string;
}
public void setEvt_impegnativa(String string) {
evt_impegnativa = string;
}
public void setEvt_note(String string) {
evt_note = string;
}
public void setEvt_filename(String string) {
evt_filename = string;
}
public String getSubjectCN() {
return subjectCN;
}
public void setSubjectCN(String string) {
subjectCN = string;
}
public boolean isEmpty() {
return ((evt_trf_codice == null) ||
(evt_trf_codice.length() < 1));
}
private Client client = null;
public void setClient(Client value) {
client = value;
subjectCN = client.user_name;
}
/**
- 162 -
APPENDICE - CODICE SORGENTE
* @return boolean true if valid, false otherwise
*/
public boolean validateEvent() {
boolean validated = true;
if((evt_trf_codice == null) ||
(evt_trf_codice.length() < 1))
validated = false;
return validated;
}
/**
* inserisce l'evento.
*
* @return boolean true if valid, false otherwise
*/
public boolean insertEvent() {
javax.activation.DataHandler dh;
try {
// Creo il FileDataSource per leggere il
file
javax.activation.FileDataSource fds = new
javax.activation.FileDataSource(evt_filename);
// Creo il DataHandler per inviare il file
dh = new javax.activation.DataHandler(fds);
} catch (Exception ex) {
dh = null;
}
try {
WSRepositorySoapBindingStub ws_client = new
WSRepositorySoapBindingStub(new URL(new
WSRepositoryServiceLocator().getWSRepositoryAddress()), new
Service());
// Allego il file se presente
if (dh != null) {
ws_client.addAttachment(dh);
}
evt_id = ws_client.openevent(client.user_id,
evt_trf_codice, evt_esterno.booleanValue(), evt_token,
evt_wslink, evt_richiedente, evt_impegnativa, evt_note);
return (evt_id > 0);
} catch (AxisFault ex) {
return false;
} catch (MalformedURLException ex) {
return false;
- 163 -
APPENDICE - CODICE SORGENTE
} catch (RemoteException ex) {
return false;
}
}
}
A.1.9 EventViewAction.java
package it.jtelemed.events;
import javax.servlet.http.*;
import org.apache.struts.action.*;
public class EventViewAction extends
org.apache.struts.action.Action {
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception
{
EventViewBean bean = (EventViewBean)form;
// Aggiungo il fileNAME
request.setAttribute("fileNAME",bean.getTokenName());
// Aggiungo il fileHREF
request.setAttribute("fileHREF",bean.getTokenTypeHref(
));
// Aggiungo il fileTYPE
request.setAttribute("fileTYPE",bean.getTokenTypeDescr
());
if (bean.viewEvent()) {
return mapping.findForward("success");
}
else {
return mapping.findForward("failure");
}
- 164 -
APPENDICE - CODICE SORGENTE
}
}
A.1.10 EventViewBean.java
package it.jtelemed.events;
import it.jtelemed.services.*;
import it.jtelemed.common.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.rmi.RemoteException;
import org.apache.axis.AxisFault;
import org.apache.axis.client.Service;
public class EventViewBean extends
org.apache.struts.action.ActionForm {
public static final long serialVersionUID = 1;
private int rep_id = 0;
private String rep_token = "";
private String rep_wslink = "";
public EventViewBean()
{
rep_id = 0;
rep_token = "";
rep_wslink = "";
}
public void setRep_id(int value) {
rep_id = value;
}
public int getRep_id() {
return rep_id;
}
public void setRep_token(String value) {
rep_token = value;
}
public String getRep_token() {
- 165 -
APPENDICE - CODICE SORGENTE
return rep_token;
}
public void setRep_wslink(String value) {
rep_wslink = value;
}
public String getRep_wslink() {
return rep_wslink;
}
public String getTokenName() {
String ext =
FileUtil.extractFileExt(rep_token).toLowerCase();
String ret = "object-" +
StringUtil.padString(Integer.toString(rep_id),12,'0',true)
+ "." + ext;
return ret;
}
public String getTokenType() {
String ext =
FileUtil.extractFileExt(rep_token).toLowerCase();
String ret = ext;
if (ext.compareTo("dcm") == 0)
ret = "dcm";
return ret;
}
public String getTokenTypeHref() {
//String ext = getTokenType();
String ret =
ServletUtil.getInitParameter(this.getServlet(),
"fileLink");
//if (ext.compareTo("dcm") == 0)
//
ret = "http://localhost/dicom/view.html?file=";
return ret;
}
public String getTokenTypeDescr() {
String ret = "";
String ext = getTokenType();
if (ext.compareTo("dcm") == 0)
ret = "Dicom";
- 166 -
APPENDICE - CODICE SORGENTE
else
ret = StringUtil.capitalizeString(ext);
return ret;
}
/**
* scarica un allegato
*
* @param String rep_id
* @param String rep_token
* @param String rep_wslink
*
* @return vero se è stato scaricato un allegato
*/
public boolean viewEvent() {
boolean hasAtt = false;
String rep_filename =
FileUtil.parsePathName(ServletUtil.getInitParameter(this.ge
tServlet(), "filePath")) +
FileUtil.getEventFileName("object",
FileUtil.extractFileExt(rep_token), rep_id);
FileUtil.logRequest("C:\\cclab.log",
"viewEvent?file=" + rep_filename);
try {
WSLaboratorySoapBindingStub ws_client = new
WSLaboratorySoapBindingStub(new URL(rep_wslink), new
Service());
// Leggo l'allegato, se presente
if (ws_client.getevent(rep_token)) {
javax.xml.soap.AttachmentPart att =
(javax.xml.soap.AttachmentPart)ws_client.getAttachments()[0
];
if (att != null) {
// Salva l'allegato
hasAtt =
Attachment.saveAttachment(att, rep_filename);
FileUtil.logRequest("C:\\cclab.log", "viewEvent:" +
new Boolean(hasAtt).toString());
}
}
} catch (AxisFault ex) {
hasAtt = false;
- 167 -
APPENDICE - CODICE SORGENTE
} catch (MalformedURLException ex) {
hasAtt = false;
} catch (RemoteException ex) {
hasAtt = false;
}
return hasAtt;
}
}
A.1.11 ReportItem.java
package it.jtelemed.reports;
public class ReportItem {
public static final long serialVersionUID = 1;
private
private
private
private
private
private
int ref_ind = 0;
String ref_filename = "";
String ref_timestamp = "";
String ref_digest = "";
String ref_notvalid = "";
String ref_author = "";
private String ref_content = "";
public ReportItem() {
ref_ind = 0;
ref_filename = "";
ref_timestamp = "";
ref_digest = "";
ref_notvalid = "";
ref_author = "";
ref_content = "";
}
public ReportItem(int ref_ind, String ref_filename,
String ref_timestamp, String ref_notvalid, String
ref_author, String ref_content) {
this.ref_ind = ref_ind;
this.ref_filename = ref_filename;
this.ref_timestamp = ref_timestamp;
this.ref_notvalid = ref_notvalid;
this.ref_author = ref_author;
- 168 -
APPENDICE - CODICE SORGENTE
this.ref_content = ref_content;
}
public void setRef_ind(int value) {
ref_ind = value;
}
public int getRef_ind() {
return ref_ind;
}
public void setRef_filename(String value) {
ref_filename = value;
}
public String getRef_filename() {
return ref_filename;
}
public void setRef_timestamp(String value) {
ref_timestamp = value;
}
public String getRef_timestamp() {
return ref_timestamp;
}
public void setRef_digest(String value) {
ref_digest = value;
}
public String getRef_digest() {
return ref_digest;
}
public void setRef_notvalid(String value) {
ref_notvalid = value;
}
public String getRef_notvalid() {
return ref_notvalid;
}
public void setRef_author(String value) {
ref_author = value;
}
public String getRef_author() {
return ref_author;
- 169 -
APPENDICE - CODICE SORGENTE
}
public void setRef_content(String value) {
ref_content = value;
}
public String getRef_content() {
return ref_content;
}
}
A.1.12 ReportList.java
package it.jtelemed.reports;
import java.util.*;
public class ReportList implements java.util.Collection {
private ArrayList list = new ArrayList();
public int size() {
return list.size();
}
public boolean isEmpty() {
return list.isEmpty();
}
public boolean contains(Object arg0) {
return list.contains(arg0);
}
public Iterator iterator() {
return list.iterator();
}
public Object[] toArray() {
return list.toArray();
}
public Object[] toArray(Object[] arg0) {
return list.toArray(arg0);
}
public boolean add(Object arg0) {
- 170 -
APPENDICE - CODICE SORGENTE
return list.add(arg0);
}
public boolean remove(Object arg0) {
return list.remove(arg0);
}
public boolean containsAll(Collection arg0) {
return list.containsAll(arg0);
}
public boolean addAll(Collection arg0) {
return list.addAll(arg0);
}
public boolean removeAll(Collection arg0) {
return list.removeAll(arg0);
}
public boolean retainAll(Collection arg0) {
return list.retainAll(arg0);
}
public void clear() {
list.clear();
}
}
A.1.13 ReportUploadAction.java
package it.jtelemed.reports;
import javax.servlet.http.*;
import it.jtelemed.common.*;
import org.apache.struts.action.*;
public class ReportUploadAction extends
org.apache.struts.action.Action {
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception
{
- 171 -
APPENDICE - CODICE SORGENTE
ReportUploadBean bean = (ReportUploadBean)form;
Client cli = Client.create(request.getSession());
bean.setClient(cli);
if (bean.upload()) {
request.setAttribute("reportUploadBean",
bean);
return mapping.findForward("success");
}
else
return mapping.findForward("failure");
}
}
A.1.14 ReportUploadBean.java
package it.jtelemed.reports;
import java.net.MalformedURLException;
import java.net.URL;
import java.rmi.RemoteException;
import org.apache.axis.AxisFault;
import org.apache.axis.client.Service;
import it.jtelemed.services.*;
import it.jtelemed.common.*;
public class ReportUploadBean extends
org.apache.struts.action.ActionForm {
public static final long serialVersionUID = 1;
private int rep_id = 0;
private String report_content = "";
public ReportUploadBean()
{
rep_id = 0;
report_content = "";
}
public void setRep_id(int value) {
rep_id = value;
}
- 172 -
APPENDICE - CODICE SORGENTE
public int getRep_id() {
return rep_id;
}
public void setReport_content(String value) {
report_content = value;
}
public String getReport_content() {
return report_content;
}
private Client client = null;
public void setClient(Client value) {
client = value;
}
public boolean upload() {
boolean uploaded = false;
String filename = "";
// Nome del file digest firmato e serializzato
filename =
FileUtil.parsePathName(client.user_archivepath) + "digest-"
+ DateTime.getTimeStamp(false) + ".bin";
// Operazione di firma del digest e
serializzazione
if (!FileUtil.createSignedFile(filename,
report_content.getBytes()))
return false;
try {
WSRepositorySoapBindingStub ws_client = new
WSRepositorySoapBindingStub(new URL(new
WSRepositoryServiceLocator().getWSRepositoryAddress()), new
Service());
// Allego il digest firmato
Attachment.addAttachmentPart(ws_client,
filename);
// Richiamo il metodo per caricare il report
sul server
if (ws_client.uploadreport(rep_id,
client.user_id, report_content)) {
- 173 -
APPENDICE - CODICE SORGENTE
uploaded = true;
}
} catch (AxisFault ex) {
return false;
} catch (MalformedURLException ex) {
return false;
} catch (RemoteException ex) {
return false;
}
return uploaded;
}
}
A.1.15 ReportViewAction.java
package it.jtelemed.reports;
import javax.servlet.http.*;
import org.apache.struts.action.*;
public class ReportViewAction extends
org.apache.struts.action.Action {
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception
{
ReportViewBean bean = (ReportViewBean)form;
if (bean.populate()) {
request.setAttribute("reportViewBean",
bean);
return mapping.findForward("success");
}
else
return mapping.findForward("failure");
}
}
- 174 -
APPENDICE - CODICE SORGENTE
A.1.16 ReportViewBean.java
package it.jtelemed.reports;
import it.jtelemed.services.*;
import it.jtelemed.common.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.rmi.RemoteException;
import org.apache.axis.AxisFault;
import org.apache.axis.client.Service;
public class ReportViewBean extends
org.apache.struts.action.ActionForm {
public static final long serialVersionUID = 1;
private int rep_id = 0;
private ReportList list = null;
private String ref_content = "";
public ReportViewBean()
{
rep_id = 0;
list = new ReportList();
ref_content = "";
}
public void setRep_id(int value) {
rep_id = value;
}
public int getRep_id() {
return rep_id;
}
public ReportList getList()
return list;
}
{
public void setList(ReportList lst) {
list = lst;
}
public void setRef_content(String value) {
ref_content = value;
}
- 175 -
APPENDICE - CODICE SORGENTE
public String getRef_content() {
return ref_content;
}
public boolean populate() {
boolean populated = false;
try {
String ref_list = "";
Object[] atts = null;
javax.xml.soap.AttachmentPart ref_attach =
null;
String ref_content = "";
ReportItem repItem;
WSRepositorySoapBindingStub ws_client = new
WSRepositorySoapBindingStub(new URL(new
WSRepositoryServiceLocator().getWSRepositoryAddress()), new
Service());
ref_list = ws_client.getreports(rep_id);
if (ref_list != null && ref_list.length() >
0) {
atts =
Attachment.getAttachments(ws_client);
String[] ref_items =
ref_list.split("§");
String[] ref_item;
if (ref_items != null &&
ref_items.length > 0) {
for (int i = 0; i <
ref_items.length; ++i)
{
ref_item =
ref_items[i].split(";");
if (ref_item != null &&
ref_item.length == 5) {
ref_content = "";
ref_attach =
(javax.xml.soap.AttachmentPart)atts[i];
if (ref_attach != null)
{
byte[] buff =
FileUtil.readFileBuffer(ref_attach);
if (buff != null &&
buff.length > 0)
ref_content =
new String(buff);
}
- 176 -
APPENDICE - CODICE SORGENTE
repItem = new
ReportItem(new Integer(ref_item[0]).intValue(),
ref_item[1], ref_item[2], ref_item[3], ref_item[4],
ref_content);
list.add(repItem);
}
}
}
}
populated = true;
} catch (AxisFault ex) {
populated = false;
} catch (MalformedURLException ex) {
populated = false;
} catch (RemoteException ex) {
populated = false;
}
return populated;
}
}
- 177 -
APPENDICE - CODICE SORGENTE
A.2 WEB SERVICE CLIENT
A.2.1 WSLaboratory.java
/**
* WSLaboratory.java
*
* This file was auto-generated from WSDL
* by the Apache Axis 1.2.1 Jun 14, 2005 (09:15:57 EDT)
WSDL2Java emitter.
*/
package it.jtelemed.services;
public interface WSLaboratory extends java.rmi.Remote {
public java.lang.String echo(java.lang.String value)
throws java.rmi.RemoteException;
public boolean getevent(java.lang.String file) throws
java.rmi.RemoteException;
}
A.2.2 WSLaboratoryService.java
/**
* WSLaboratoryService.java
*
* This file was auto-generated from WSDL
* by the Apache Axis 1.2.1 Jun 14, 2005 (09:15:57 EDT)
WSDL2Java emitter.
*/
package it.jtelemed.services;
public interface WSLaboratoryService extends
javax.xml.rpc.Service {
public java.lang.String getWSLaboratoryAddress();
public it.jtelemed.services.WSLaboratory
getWSLaboratory() throws javax.xml.rpc.ServiceException;
- 178 -
APPENDICE - CODICE SORGENTE
public it.jtelemed.services.WSLaboratory
getWSLaboratory(java.net.URL portAddress) throws
javax.xml.rpc.ServiceException;
}
A.2.3 WSLaboratoryServiceLocator.java
/**
* WSLaboratoryServiceLocator.java
*
* This file was auto-generated from WSDL
* by the Apache Axis 1.2.1 Jun 14, 2005 (09:15:57 EDT)
WSDL2Java emitter.
*/
package it.jtelemed.services;
public class WSLaboratoryServiceLocator extends
org.apache.axis.client.Service implements
it.jtelemed.services.WSLaboratoryService {
public static final long serialVersionUID = 1;
public WSLaboratoryServiceLocator() {
}
public
WSLaboratoryServiceLocator(org.apache.axis.EngineConfigurat
ion config) {
super(config);
}
public WSLaboratoryServiceLocator(java.lang.String
wsdlLoc, javax.xml.namespace.QName sName) throws
javax.xml.rpc.ServiceException {
super(wsdlLoc, sName);
}
// Use to get a proxy class for WSLaboratory
private java.lang.String WSLaboratory_address =
"http://cityhunter:9090/jtelemed_wslab/services/WSLaborator
y";
public java.lang.String getWSLaboratoryAddress() {
return WSLaboratory_address;
- 179 -
APPENDICE - CODICE SORGENTE
}
// The WSDD service name defaults to the port name.
private java.lang.String WSLaboratoryWSDDServiceName =
"WSLaboratory";
public java.lang.String
getWSLaboratoryWSDDServiceName() {
return WSLaboratoryWSDDServiceName;
}
public void
setWSLaboratoryWSDDServiceName(java.lang.String name) {
WSLaboratoryWSDDServiceName = name;
}
public it.jtelemed.services.WSLaboratory
getWSLaboratory() throws javax.xml.rpc.ServiceException {
java.net.URL endpoint;
try {
endpoint = new
java.net.URL(WSLaboratory_address);
}
catch (java.net.MalformedURLException e) {
throw new javax.xml.rpc.ServiceException(e);
}
return getWSLaboratory(endpoint);
}
public it.jtelemed.services.WSLaboratory
getWSLaboratory(java.net.URL portAddress) throws
javax.xml.rpc.ServiceException {
try {
it.jtelemed.services.WSLaboratorySoapBindingStub _stub =
new
it.jtelemed.services.WSLaboratorySoapBindingStub(portAddres
s, this);
_stub.setPortName(getWSLaboratoryWSDDServiceName());
return _stub;
}
catch (org.apache.axis.AxisFault e) {
return null;
}
}
public void
setWSLaboratoryEndpointAddress(java.lang.String address) {
WSLaboratory_address = address;
- 180 -
APPENDICE - CODICE SORGENTE
}
/**
* For the given interface, get the stub
implementation.
* If this service has no port for the given interface,
* then ServiceException is thrown.
*/
public java.rmi.Remote getPort(Class
serviceEndpointInterface) throws
javax.xml.rpc.ServiceException {
try {
if
(it.jtelemed.services.WSLaboratory.class.isAssignableFrom(s
erviceEndpointInterface)) {
it.jtelemed.services.WSLaboratorySoapBindingStub _stub =
new it.jtelemed.services.WSLaboratorySoapBindingStub(new
java.net.URL(WSLaboratory_address), this);
_stub.setPortName(getWSLaboratoryWSDDServiceName());
return _stub;
}
}
catch (java.lang.Throwable t) {
throw new javax.xml.rpc.ServiceException(t);
}
throw new javax.xml.rpc.ServiceException("There is
no stub implementation for the interface: " +
(serviceEndpointInterface == null ? "null" :
serviceEndpointInterface.getName()));
}
/**
* For the given interface, get the stub
implementation.
* If this service has no port for the given interface,
* then ServiceException is thrown.
*/
public java.rmi.Remote
getPort(javax.xml.namespace.QName portName, Class
serviceEndpointInterface) throws
javax.xml.rpc.ServiceException {
if (portName == null) {
return getPort(serviceEndpointInterface);
}
java.lang.String inputPortName =
portName.getLocalPart();
if ("WSLaboratory".equals(inputPortName)) {
return getWSLaboratory();
- 181 -
APPENDICE - CODICE SORGENTE
}
else {
java.rmi.Remote _stub =
getPort(serviceEndpointInterface);
((org.apache.axis.client.Stub)
_stub).setPortName(portName);
return _stub;
}
}
public javax.xml.namespace.QName getServiceName() {
return new
javax.xml.namespace.QName("http://services.jtelemed.it",
"WSLaboratoryService");
}
private java.util.HashSet ports = null;
public java.util.Iterator getPorts() {
if (ports == null) {
ports = new java.util.HashSet();
ports.add(new
javax.xml.namespace.QName("http://services.jtelemed.it",
"WSLaboratory"));
}
return ports.iterator();
}
/**
* Set the endpoint address for the specified port name.
*/
public void setEndpointAddress(java.lang.String
portName, java.lang.String address) throws
javax.xml.rpc.ServiceException {
if ("WSLaboratory".equals(portName)) {
setWSLaboratoryEndpointAddress(address);
}
else
{ // Unknown Port Name
throw new javax.xml.rpc.ServiceException("
Cannot set Endpoint Address for Unknown Port" + portName);
}
}
/**
* Set the endpoint address for the specified port name.
*/
public void
setEndpointAddress(javax.xml.namespace.QName portName,
- 182 -
APPENDICE - CODICE SORGENTE
java.lang.String address) throws
javax.xml.rpc.ServiceException {
setEndpointAddress(portName.getLocalPart(),
address);
}
}
A.2.4 WSLaboratorySoapBindingStub.java
/**
* WSLaboratorySoapBindingStub.java
*
* This file was auto-generated from WSDL
* by the Apache Axis 1.2.1 Jun 14, 2005 (09:15:57 EDT)
WSDL2Java emitter.
*/
package it.jtelemed.services;
public class WSLaboratorySoapBindingStub extends
org.apache.axis.client.Stub implements
it.jtelemed.services.WSLaboratory {
/*
private java.util.Vector cachedSerClasses = new
java.util.Vector();
private java.util.Vector cachedSerQNames = new
java.util.Vector();
private java.util.Vector cachedSerFactories = new
java.util.Vector();
private java.util.Vector cachedDeserFactories = new
java.util.Vector();
*/
static org.apache.axis.description.OperationDesc []
_operations;
static {
_operations = new
org.apache.axis.description.OperationDesc[2];
_initOperationDesc1();
}
private static void _initOperationDesc1(){
org.apache.axis.description.OperationDesc oper;
org.apache.axis.description.ParameterDesc param;
- 183 -
APPENDICE - CODICE SORGENTE
oper = new
org.apache.axis.description.OperationDesc();
oper.setName("echo");
param = new
org.apache.axis.description.ParameterDesc(new
javax.xml.namespace.QName("", "value"),
org.apache.axis.description.ParameterDesc.IN, new
javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema
", "string"), java.lang.String.class, false, false);
oper.addParameter(param);
oper.setReturnType(new
javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema
", "string"));
oper.setReturnClass(java.lang.String.class);
oper.setReturnQName(new
javax.xml.namespace.QName("", "echoReturn"));
oper.setStyle(org.apache.axis.constants.Style.RPC);
oper.setUse(org.apache.axis.constants.Use.ENCODED);
_operations[0] = oper;
oper = new
org.apache.axis.description.OperationDesc();
oper.setName("getevent");
param = new
org.apache.axis.description.ParameterDesc(new
javax.xml.namespace.QName("", "file"),
org.apache.axis.description.ParameterDesc.IN, new
javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema
", "string"), java.lang.String.class, false, false);
oper.addParameter(param);
oper.setReturnType(new
javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema
", "boolean"));
oper.setReturnClass(boolean.class);
oper.setReturnQName(new
javax.xml.namespace.QName("", "geteventReturn"));
oper.setStyle(org.apache.axis.constants.Style.RPC);
oper.setUse(org.apache.axis.constants.Use.ENCODED);
_operations[1] = oper;
}
public WSLaboratorySoapBindingStub() throws
org.apache.axis.AxisFault {
this(null);
}
public WSLaboratorySoapBindingStub(java.net.URL
endpointURL, javax.xml.rpc.Service service) throws
org.apache.axis.AxisFault {
- 184 -
APPENDICE - CODICE SORGENTE
this(service);
super.cachedEndpoint = endpointURL;
}
public
WSLaboratorySoapBindingStub(javax.xml.rpc.Service service)
throws org.apache.axis.AxisFault {
if (service == null) {
super.service = new
org.apache.axis.client.Service();
} else {
super.service = service;
}
((org.apache.axis.client.Service)super.service).setTypeMapp
ingVersion("1.2");
}
protected org.apache.axis.client.Call createCall()
throws java.rmi.RemoteException {
try {
org.apache.axis.client.Call _call =
super._createCall();
if (super.maintainSessionSet) {
_call.setMaintainSession(super.maintainSession);
}
if (super.cachedUsername != null) {
_call.setUsername(super.cachedUsername);
}
if (super.cachedPassword != null) {
_call.setPassword(super.cachedPassword);
}
if (super.cachedEndpoint != null) {
_call.setTargetEndpointAddress(super.cachedEndpoint);
}
if (super.cachedTimeout != null) {
_call.setTimeout(super.cachedTimeout);
}
if (super.cachedPortName != null) {
_call.setPortName(super.cachedPortName);
}
java.util.Enumeration keys =
super.cachedProperties.keys();
while (keys.hasMoreElements()) {
java.lang.String key = (java.lang.String)
keys.nextElement();
_call.setProperty(key,
super.cachedProperties.get(key));
- 185 -
APPENDICE - CODICE SORGENTE
}
return _call;
}
catch (java.lang.Throwable _t) {
throw new org.apache.axis.AxisFault("Failure
trying to get the Call object", _t);
}
}
public java.lang.String echo(java.lang.String value)
throws java.rmi.RemoteException {
if (super.cachedEndpoint == null) {
throw new
org.apache.axis.NoEndPointException();
}
org.apache.axis.client.Call _call = createCall();
_call.setOperation(_operations[0]);
_call.setUseSOAPAction(true);
_call.setSOAPActionURI("");
_call.setSOAPVersion(org.apache.axis.soap.SOAPConstants.SOA
P11_CONSTANTS);
_call.setOperationName(new
javax.xml.namespace.QName("http://services.jtelemed.it",
"echo"));
setRequestHeaders(_call);
setAttachments(_call);
try {
java.lang.Object _resp = _call.invoke(new
java.lang.Object[] {value});
if (_resp instanceof java.rmi.RemoteException) {
throw (java.rmi.RemoteException)_resp;
}
else {
extractAttachments(_call);
try {
return (java.lang.String) _resp;
} catch (java.lang.Exception _exception) {
return (java.lang.String)
org.apache.axis.utils.JavaUtils.convert(_resp,
java.lang.String.class);
}
}
} catch (org.apache.axis.AxisFault axisFaultException) {
throw axisFaultException;
}
}
- 186 -
APPENDICE - CODICE SORGENTE
public boolean getevent(java.lang.String file) throws
java.rmi.RemoteException {
if (super.cachedEndpoint == null) {
throw new
org.apache.axis.NoEndPointException();
}
org.apache.axis.client.Call _call = createCall();
_call.setOperation(_operations[1]);
_call.setUseSOAPAction(true);
_call.setSOAPActionURI("");
_call.setSOAPVersion(org.apache.axis.soap.SOAPConstants.SOA
P11_CONSTANTS);
_call.setOperationName(new
javax.xml.namespace.QName("http://services.jtelemed.it",
"getevent"));
setRequestHeaders(_call);
setAttachments(_call);
try {
java.lang.Object _resp = _call.invoke(new
java.lang.Object[] {file});
if (_resp instanceof java.rmi.RemoteException) {
throw (java.rmi.RemoteException)_resp;
}
else {
extractAttachments(_call);
try {
return ((java.lang.Boolean)
_resp).booleanValue();
} catch (java.lang.Exception _exception) {
return ((java.lang.Boolean)
org.apache.axis.utils.JavaUtils.convert(_resp,
boolean.class)).booleanValue();
}
}
} catch (org.apache.axis.AxisFault axisFaultException) {
throw axisFaultException;
}
}
}
- 187 -
APPENDICE - CODICE SORGENTE
A.2.5 WSRepository.java
/**
* WSRepository.java
*
* This file was auto-generated from WSDL
* by the Apache Axis 1.2.1 Jun 14, 2005 (09:15:57 EDT)
WSDL2Java emitter.
*/
package it.jtelemed.services;
public interface WSRepository extends java.rmi.Remote {
public java.lang.String echo(java.lang.String value)
throws java.rmi.RemoteException;
public java.lang.String userinfo(java.lang.String
utn_cn) throws java.rmi.RemoteException;
public java.lang.String listevents(int utn_id) throws
java.rmi.RemoteException;
public int openevent(int utn_id, java.lang.String
evt_codice, boolean evt_esterno, java.lang.String
evt_token, java.lang.String evt_wslink, java.lang.String
evt_richiedente, java.lang.String evt_impegnativa,
java.lang.String evt_note) throws java.rmi.RemoteException;
public boolean closeevent(int evt_id) throws
java.rmi.RemoteException;
public java.lang.String getreports(int evt_id) throws
java.rmi.RemoteException;
public boolean uploadreport(int evt_id, int utn_id,
java.lang.String evt_content) throws
java.rmi.RemoteException;
public boolean invalidatereport(int evt_id, int
ref_ind) throws java.rmi.RemoteException;
}
A.2.6 WSRepositoryService.java
/**
* WSRepositoryService.java
*
* This file was auto-generated from WSDL
* by the Apache Axis 1.2.1 Jun 14, 2005 (09:15:57 EDT)
WSDL2Java emitter.
*/
- 188 -
APPENDICE - CODICE SORGENTE
package it.jtelemed.services;
public interface WSRepositoryService extends
javax.xml.rpc.Service {
public java.lang.String getWSRepositoryAddress();
public it.jtelemed.services.WSRepository
getWSRepository() throws javax.xml.rpc.ServiceException;
public it.jtelemed.services.WSRepository
getWSRepository(java.net.URL portAddress) throws
javax.xml.rpc.ServiceException;
}
A.2.7 WSRepositoryServiceLocator.java
/**
* WSRepositoryServiceLocator.java
*
* This file was auto-generated from WSDL
* by the Apache Axis 1.2.1 Jun 14, 2005 (09:15:57 EDT)
WSDL2Java emitter.
*/
package it.jtelemed.services;
public class WSRepositoryServiceLocator extends
org.apache.axis.client.Service implements
it.jtelemed.services.WSRepositoryService {
public static final long serialVersionUID = 1;
public WSRepositoryServiceLocator() {
}
public
WSRepositoryServiceLocator(org.apache.axis.EngineConfigurat
ion config) {
super(config);
}
public WSRepositoryServiceLocator(java.lang.String
wsdlLoc, javax.xml.namespace.QName sName) throws
javax.xml.rpc.ServiceException {
super(wsdlLoc, sName);
- 189 -
APPENDICE - CODICE SORGENTE
}
// Use to get a proxy class for WSRepository
private java.lang.String WSRepository_address =
"http://cityhunter:9090/jtelemed/services/WSRepository";
public java.lang.String getWSRepositoryAddress() {
return WSRepository_address;
}
// The WSDD service name defaults to the port name.
private java.lang.String WSRepositoryWSDDServiceName =
"WSRepository";
public java.lang.String
getWSRepositoryWSDDServiceName() {
return WSRepositoryWSDDServiceName;
}
public void
setWSRepositoryWSDDServiceName(java.lang.String name) {
WSRepositoryWSDDServiceName = name;
}
public it.jtelemed.services.WSRepository
getWSRepository() throws javax.xml.rpc.ServiceException {
java.net.URL endpoint;
try {
endpoint = new
java.net.URL(WSRepository_address);
}
catch (java.net.MalformedURLException e) {
throw new javax.xml.rpc.ServiceException(e);
}
return getWSRepository(endpoint);
}
public it.jtelemed.services.WSRepository
getWSRepository(java.net.URL portAddress) throws
javax.xml.rpc.ServiceException {
try {
it.jtelemed.services.WSRepositorySoapBindingStub _stub =
new
it.jtelemed.services.WSRepositorySoapBindingStub(portAddres
s, this);
_stub.setPortName(getWSRepositoryWSDDServiceName());
return _stub;
}
- 190 -
APPENDICE - CODICE SORGENTE
catch (org.apache.axis.AxisFault e) {
return null;
}
}
public void
setWSRepositoryEndpointAddress(java.lang.String address) {
WSRepository_address = address;
}
/**
* For the given interface, get the stub
implementation.
* If this service has no port for the given interface,
* then ServiceException is thrown.
*/
public java.rmi.Remote getPort(Class
serviceEndpointInterface) throws
javax.xml.rpc.ServiceException {
try {
if
(it.jtelemed.services.WSRepository.class.isAssignableFrom(s
erviceEndpointInterface)) {
it.jtelemed.services.WSRepositorySoapBindingStub _stub =
new it.jtelemed.services.WSRepositorySoapBindingStub(new
java.net.URL(WSRepository_address), this);
_stub.setPortName(getWSRepositoryWSDDServiceName());
return _stub;
}
}
catch (java.lang.Throwable t) {
throw new javax.xml.rpc.ServiceException(t);
}
throw new javax.xml.rpc.ServiceException("There is
no stub implementation for the interface: " +
(serviceEndpointInterface == null ? "null" :
serviceEndpointInterface.getName()));
}
/**
* For the given interface, get the stub
implementation.
* If this service has no port for the given interface,
* then ServiceException is thrown.
*/
public java.rmi.Remote
getPort(javax.xml.namespace.QName portName, Class
- 191 -
APPENDICE - CODICE SORGENTE
serviceEndpointInterface) throws
javax.xml.rpc.ServiceException {
if (portName == null) {
return getPort(serviceEndpointInterface);
}
java.lang.String inputPortName =
portName.getLocalPart();
if ("WSRepository".equals(inputPortName)) {
return getWSRepository();
}
else {
java.rmi.Remote _stub =
getPort(serviceEndpointInterface);
((org.apache.axis.client.Stub)
_stub).setPortName(portName);
return _stub;
}
}
public javax.xml.namespace.QName getServiceName() {
return new
javax.xml.namespace.QName("http://services.jtelemed.it",
"WSRepositoryService");
}
private java.util.HashSet ports = null;
public java.util.Iterator getPorts() {
if (ports == null) {
ports = new java.util.HashSet();
ports.add(new
javax.xml.namespace.QName("http://services.jtelemed.it",
"WSRepository"));
}
return ports.iterator();
}
/**
* Set the endpoint address for the specified port name.
*/
public void setEndpointAddress(java.lang.String
portName, java.lang.String address) throws
javax.xml.rpc.ServiceException {
if ("WSRepository".equals(portName)) {
setWSRepositoryEndpointAddress(address);
}
else
{ // Unknown Port Name
- 192 -
APPENDICE - CODICE SORGENTE
throw new javax.xml.rpc.ServiceException("
Cannot set Endpoint Address for Unknown Port" + portName);
}
}
/**
* Set the endpoint address for the specified port name.
*/
public void
setEndpointAddress(javax.xml.namespace.QName portName,
java.lang.String address) throws
javax.xml.rpc.ServiceException {
setEndpointAddress(portName.getLocalPart(),
address);
}
}
A.2.8 WSRepositorySoapBindingStub.java
/**
* WSRepositorySoapBindingStub.java
*
* This file was auto-generated from WSDL
* by the Apache Axis 1.2.1 Jun 14, 2005 (09:15:57 EDT)
WSDL2Java emitter.
*/
package it.jtelemed.services;
public class WSRepositorySoapBindingStub extends
org.apache.axis.client.Stub implements
it.jtelemed.services.WSRepository {
/*
private java.util.Vector cachedSerClasses = new
java.util.Vector();
private java.util.Vector cachedSerQNames = new
java.util.Vector();
private java.util.Vector cachedSerFactories = new
java.util.Vector();
private java.util.Vector cachedDeserFactories = new
java.util.Vector();
*/
- 193 -
APPENDICE - CODICE SORGENTE
static org.apache.axis.description.OperationDesc []
_operations;
static {
_operations = new
org.apache.axis.description.OperationDesc[8];
_initOperationDesc1();
}
private static void _initOperationDesc1(){
org.apache.axis.description.OperationDesc oper;
org.apache.axis.description.ParameterDesc param;
oper = new
org.apache.axis.description.OperationDesc();
oper.setName("echo");
param = new
org.apache.axis.description.ParameterDesc(new
javax.xml.namespace.QName("", "value"),
org.apache.axis.description.ParameterDesc.IN, new
javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema
", "string"), java.lang.String.class, false, false);
oper.addParameter(param);
oper.setReturnType(new
javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema
", "string"));
oper.setReturnClass(java.lang.String.class);
oper.setReturnQName(new
javax.xml.namespace.QName("", "echoReturn"));
oper.setStyle(org.apache.axis.constants.Style.RPC);
oper.setUse(org.apache.axis.constants.Use.ENCODED);
_operations[0] = oper;
oper = new
org.apache.axis.description.OperationDesc();
oper.setName("userinfo");
param = new
org.apache.axis.description.ParameterDesc(new
javax.xml.namespace.QName("", "utn_cn"),
org.apache.axis.description.ParameterDesc.IN, new
javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema
", "string"), java.lang.String.class, false, false);
oper.addParameter(param);
oper.setReturnType(new
javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema
", "string"));
oper.setReturnClass(java.lang.String.class);
oper.setReturnQName(new
javax.xml.namespace.QName("", "userinfoReturn"));
oper.setStyle(org.apache.axis.constants.Style.RPC);
oper.setUse(org.apache.axis.constants.Use.ENCODED);
- 194 -
APPENDICE - CODICE SORGENTE
_operations[1] = oper;
oper = new
org.apache.axis.description.OperationDesc();
oper.setName("listevents");
param = new
org.apache.axis.description.ParameterDesc(new
javax.xml.namespace.QName("", "utn_id"),
org.apache.axis.description.ParameterDesc.IN, new
javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema
", "int"), int.class, false, false);
oper.addParameter(param);
oper.setReturnType(new
javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema
", "string"));
oper.setReturnClass(java.lang.String.class);
oper.setReturnQName(new
javax.xml.namespace.QName("", "listeventsReturn"));
oper.setStyle(org.apache.axis.constants.Style.RPC);
oper.setUse(org.apache.axis.constants.Use.ENCODED);
_operations[2] = oper;
oper = new
org.apache.axis.description.OperationDesc();
oper.setName("openevent");
param = new
org.apache.axis.description.ParameterDesc(new
javax.xml.namespace.QName("", "utn_id"),
org.apache.axis.description.ParameterDesc.IN, new
javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema
", "int"), int.class, false, false);
oper.addParameter(param);
param = new
org.apache.axis.description.ParameterDesc(new
javax.xml.namespace.QName("", "evt_codice"),
org.apache.axis.description.ParameterDesc.IN, new
javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema
", "string"), java.lang.String.class, false, false);
oper.addParameter(param);
param = new
org.apache.axis.description.ParameterDesc(new
javax.xml.namespace.QName("", "evt_esterno"),
org.apache.axis.description.ParameterDesc.IN, new
javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema
", "boolean"), boolean.class, false, false);
oper.addParameter(param);
param = new
org.apache.axis.description.ParameterDesc(new
javax.xml.namespace.QName("", "evt_token"),
org.apache.axis.description.ParameterDesc.IN, new
- 195 -
APPENDICE - CODICE SORGENTE
javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema
", "string"), java.lang.String.class, false, false);
oper.addParameter(param);
param = new
org.apache.axis.description.ParameterDesc(new
javax.xml.namespace.QName("", "evt_wslink"),
org.apache.axis.description.ParameterDesc.IN, new
javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema
", "string"), java.lang.String.class, false, false);
oper.addParameter(param);
param = new
org.apache.axis.description.ParameterDesc(new
javax.xml.namespace.QName("", "evt_richiedente"),
org.apache.axis.description.ParameterDesc.IN, new
javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema
", "string"), java.lang.String.class, false, false);
oper.addParameter(param);
param = new
org.apache.axis.description.ParameterDesc(new
javax.xml.namespace.QName("", "evt_impegnativa"),
org.apache.axis.description.ParameterDesc.IN, new
javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema
", "string"), java.lang.String.class, false, false);
oper.addParameter(param);
param = new
org.apache.axis.description.ParameterDesc(new
javax.xml.namespace.QName("", "evt_note"),
org.apache.axis.description.ParameterDesc.IN, new
javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema
", "string"), java.lang.String.class, false, false);
oper.addParameter(param);
oper.setReturnType(new
javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema
", "int"));
oper.setReturnClass(int.class);
oper.setReturnQName(new
javax.xml.namespace.QName("", "openeventReturn"));
oper.setStyle(org.apache.axis.constants.Style.RPC);
oper.setUse(org.apache.axis.constants.Use.ENCODED);
_operations[3] = oper;
oper = new
org.apache.axis.description.OperationDesc();
oper.setName("closeevent");
param = new
org.apache.axis.description.ParameterDesc(new
javax.xml.namespace.QName("", "evt_id"),
org.apache.axis.description.ParameterDesc.IN, new
javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema
", "int"), int.class, false, false);
- 196 -
APPENDICE - CODICE SORGENTE
oper.addParameter(param);
oper.setReturnType(new
javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema
", "boolean"));
oper.setReturnClass(boolean.class);
oper.setReturnQName(new
javax.xml.namespace.QName("", "closeeventReturn"));
oper.setStyle(org.apache.axis.constants.Style.RPC);
oper.setUse(org.apache.axis.constants.Use.ENCODED);
_operations[4] = oper;
oper = new
org.apache.axis.description.OperationDesc();
oper.setName("getreports");
param = new
org.apache.axis.description.ParameterDesc(new
javax.xml.namespace.QName("", "evt_id"),
org.apache.axis.description.ParameterDesc.IN, new
javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema
", "int"), int.class, false, false);
oper.addParameter(param);
oper.setReturnType(new
javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema
", "string"));
oper.setReturnClass(java.lang.String.class);
oper.setReturnQName(new
javax.xml.namespace.QName("", "getreportsReturn"));
oper.setStyle(org.apache.axis.constants.Style.RPC);
oper.setUse(org.apache.axis.constants.Use.ENCODED);
_operations[5] = oper;
oper = new
org.apache.axis.description.OperationDesc();
oper.setName("uploadreport");
param = new
org.apache.axis.description.ParameterDesc(new
javax.xml.namespace.QName("", "evt_id"),
org.apache.axis.description.ParameterDesc.IN, new
javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema
", "int"), int.class, false, false);
oper.addParameter(param);
param = new
org.apache.axis.description.ParameterDesc(new
javax.xml.namespace.QName("", "utn_id"),
org.apache.axis.description.ParameterDesc.IN, new
javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema
", "int"), int.class, false, false);
oper.addParameter(param);
param = new
org.apache.axis.description.ParameterDesc(new
- 197 -
APPENDICE - CODICE SORGENTE
javax.xml.namespace.QName("", "evt_content"),
org.apache.axis.description.ParameterDesc.IN, new
javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema
", "string"), java.lang.String.class, false, false);
oper.addParameter(param);
oper.setReturnType(new
javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema
", "boolean"));
oper.setReturnClass(boolean.class);
oper.setReturnQName(new
javax.xml.namespace.QName("", "uploadreportReturn"));
oper.setStyle(org.apache.axis.constants.Style.RPC);
oper.setUse(org.apache.axis.constants.Use.ENCODED);
_operations[6] = oper;
oper = new
org.apache.axis.description.OperationDesc();
oper.setName("invalidatereport");
param = new
org.apache.axis.description.ParameterDesc(new
javax.xml.namespace.QName("", "evt_id"),
org.apache.axis.description.ParameterDesc.IN, new
javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema
", "int"), int.class, false, false);
oper.addParameter(param);
param = new
org.apache.axis.description.ParameterDesc(new
javax.xml.namespace.QName("", "ref_ind"),
org.apache.axis.description.ParameterDesc.IN, new
javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema
", "int"), int.class, false, false);
oper.addParameter(param);
oper.setReturnType(new
javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema
", "boolean"));
oper.setReturnClass(boolean.class);
oper.setReturnQName(new
javax.xml.namespace.QName("", "invalidatereportReturn"));
oper.setStyle(org.apache.axis.constants.Style.RPC);
oper.setUse(org.apache.axis.constants.Use.ENCODED);
_operations[7] = oper;
}
public WSRepositorySoapBindingStub() throws
org.apache.axis.AxisFault {
this(null);
}
- 198 -
APPENDICE - CODICE SORGENTE
public WSRepositorySoapBindingStub(java.net.URL
endpointURL, javax.xml.rpc.Service service) throws
org.apache.axis.AxisFault {
this(service);
super.cachedEndpoint = endpointURL;
}
public
WSRepositorySoapBindingStub(javax.xml.rpc.Service service)
throws org.apache.axis.AxisFault {
if (service == null) {
super.service = new
org.apache.axis.client.Service();
} else {
super.service = service;
}
((org.apache.axis.client.Service)super.service).setTypeMapp
ingVersion("1.2");
}
protected org.apache.axis.client.Call createCall()
throws java.rmi.RemoteException {
try {
org.apache.axis.client.Call _call =
super._createCall();
if (super.maintainSessionSet) {
_call.setMaintainSession(super.maintainSession);
}
if (super.cachedUsername != null) {
_call.setUsername(super.cachedUsername);
}
if (super.cachedPassword != null) {
_call.setPassword(super.cachedPassword);
}
if (super.cachedEndpoint != null) {
_call.setTargetEndpointAddress(super.cachedEndpoint);
}
if (super.cachedTimeout != null) {
_call.setTimeout(super.cachedTimeout);
}
if (super.cachedPortName != null) {
_call.setPortName(super.cachedPortName);
}
java.util.Enumeration keys =
super.cachedProperties.keys();
while (keys.hasMoreElements()) {
- 199 -
APPENDICE - CODICE SORGENTE
java.lang.String key = (java.lang.String)
keys.nextElement();
_call.setProperty(key,
super.cachedProperties.get(key));
}
return _call;
}
catch (java.lang.Throwable _t) {
throw new org.apache.axis.AxisFault("Failure
trying to get the Call object", _t);
}
}
public java.lang.String echo(java.lang.String value)
throws java.rmi.RemoteException {
if (super.cachedEndpoint == null) {
throw new
org.apache.axis.NoEndPointException();
}
org.apache.axis.client.Call _call = createCall();
_call.setOperation(_operations[0]);
_call.setUseSOAPAction(true);
_call.setSOAPActionURI("");
_call.setSOAPVersion(org.apache.axis.soap.SOAPConstants.SOA
P11_CONSTANTS);
_call.setOperationName(new
javax.xml.namespace.QName("http://services.jtelemed.it",
"echo"));
setRequestHeaders(_call);
setAttachments(_call);
try {
java.lang.Object _resp = _call.invoke(new
java.lang.Object[] {value});
if (_resp instanceof java.rmi.RemoteException) {
throw (java.rmi.RemoteException)_resp;
}
else {
extractAttachments(_call);
try {
return (java.lang.String) _resp;
} catch (java.lang.Exception _exception) {
return (java.lang.String)
org.apache.axis.utils.JavaUtils.convert(_resp,
java.lang.String.class);
}
}
} catch (org.apache.axis.AxisFault axisFaultException) {
throw axisFaultException;
- 200 -
APPENDICE - CODICE SORGENTE
}
}
public java.lang.String userinfo(java.lang.String
utn_cn) throws java.rmi.RemoteException {
if (super.cachedEndpoint == null) {
throw new
org.apache.axis.NoEndPointException();
}
org.apache.axis.client.Call _call = createCall();
_call.setOperation(_operations[1]);
_call.setUseSOAPAction(true);
_call.setSOAPActionURI("");
_call.setSOAPVersion(org.apache.axis.soap.SOAPConstants.SOA
P11_CONSTANTS);
_call.setOperationName(new
javax.xml.namespace.QName("http://services.jtelemed.it",
"userinfo"));
setRequestHeaders(_call);
setAttachments(_call);
try {
java.lang.Object _resp = _call.invoke(new
java.lang.Object[] {utn_cn});
if (_resp instanceof java.rmi.RemoteException) {
throw (java.rmi.RemoteException)_resp;
}
else {
extractAttachments(_call);
try {
return (java.lang.String) _resp;
} catch (java.lang.Exception _exception) {
return (java.lang.String)
org.apache.axis.utils.JavaUtils.convert(_resp,
java.lang.String.class);
}
}
} catch (org.apache.axis.AxisFault axisFaultException) {
throw axisFaultException;
}
}
public java.lang.String listevents(int utn_id) throws
java.rmi.RemoteException {
if (super.cachedEndpoint == null) {
throw new
org.apache.axis.NoEndPointException();
}
org.apache.axis.client.Call _call = createCall();
- 201 -
APPENDICE - CODICE SORGENTE
_call.setOperation(_operations[2]);
_call.setUseSOAPAction(true);
_call.setSOAPActionURI("");
_call.setSOAPVersion(org.apache.axis.soap.SOAPConstants.SOA
P11_CONSTANTS);
_call.setOperationName(new
javax.xml.namespace.QName("http://services.jtelemed.it",
"listevents"));
setRequestHeaders(_call);
setAttachments(_call);
try {
java.lang.Object _resp = _call.invoke(new
java.lang.Object[] {new java.lang.Integer(utn_id)});
if (_resp instanceof java.rmi.RemoteException) {
throw (java.rmi.RemoteException)_resp;
}
else {
extractAttachments(_call);
try {
return (java.lang.String) _resp;
} catch (java.lang.Exception _exception) {
return (java.lang.String)
org.apache.axis.utils.JavaUtils.convert(_resp,
java.lang.String.class);
}
}
} catch (org.apache.axis.AxisFault axisFaultException) {
throw axisFaultException;
}
}
public int openevent(int utn_id, java.lang.String
evt_codice, boolean evt_esterno, java.lang.String
evt_token, java.lang.String evt_wslink, java.lang.String
evt_richiedente, java.lang.String evt_impegnativa,
java.lang.String evt_note) throws java.rmi.RemoteException
{
if (super.cachedEndpoint == null) {
throw new
org.apache.axis.NoEndPointException();
}
org.apache.axis.client.Call _call = createCall();
_call.setOperation(_operations[3]);
_call.setUseSOAPAction(true);
_call.setSOAPActionURI("");
_call.setSOAPVersion(org.apache.axis.soap.SOAPConstants.SOA
P11_CONSTANTS);
- 202 -
APPENDICE - CODICE SORGENTE
_call.setOperationName(new
javax.xml.namespace.QName("http://services.jtelemed.it",
"openevent"));
setRequestHeaders(_call);
setAttachments(_call);
try {
java.lang.Object _resp = _call.invoke(new
java.lang.Object[] {new java.lang.Integer(utn_id),
evt_codice, new java.lang.Boolean(evt_esterno), evt_token,
evt_wslink, evt_richiedente, evt_impegnativa, evt_note});
if (_resp instanceof java.rmi.RemoteException) {
throw (java.rmi.RemoteException)_resp;
}
else {
extractAttachments(_call);
try {
return ((java.lang.Integer)
_resp).intValue();
} catch (java.lang.Exception _exception) {
return ((java.lang.Integer)
org.apache.axis.utils.JavaUtils.convert(_resp,
int.class)).intValue();
}
}
} catch (org.apache.axis.AxisFault axisFaultException) {
throw axisFaultException;
}
}
public boolean closeevent(int evt_id) throws
java.rmi.RemoteException {
if (super.cachedEndpoint == null) {
throw new
org.apache.axis.NoEndPointException();
}
org.apache.axis.client.Call _call = createCall();
_call.setOperation(_operations[4]);
_call.setUseSOAPAction(true);
_call.setSOAPActionURI("");
_call.setSOAPVersion(org.apache.axis.soap.SOAPConstants.SOA
P11_CONSTANTS);
_call.setOperationName(new
javax.xml.namespace.QName("http://services.jtelemed.it",
"closeevent"));
setRequestHeaders(_call);
setAttachments(_call);
- 203 -
APPENDICE - CODICE SORGENTE
try {
java.lang.Object _resp = _call.invoke(new
java.lang.Object[] {new java.lang.Integer(evt_id)});
if (_resp instanceof java.rmi.RemoteException) {
throw (java.rmi.RemoteException)_resp;
}
else {
extractAttachments(_call);
try {
return ((java.lang.Boolean)
_resp).booleanValue();
} catch (java.lang.Exception _exception) {
return ((java.lang.Boolean)
org.apache.axis.utils.JavaUtils.convert(_resp,
boolean.class)).booleanValue();
}
}
} catch (org.apache.axis.AxisFault axisFaultException) {
throw axisFaultException;
}
}
public java.lang.String getreports(int evt_id) throws
java.rmi.RemoteException {
if (super.cachedEndpoint == null) {
throw new
org.apache.axis.NoEndPointException();
}
org.apache.axis.client.Call _call = createCall();
_call.setOperation(_operations[5]);
_call.setUseSOAPAction(true);
_call.setSOAPActionURI("");
_call.setSOAPVersion(org.apache.axis.soap.SOAPConstants.SOA
P11_CONSTANTS);
_call.setOperationName(new
javax.xml.namespace.QName("http://services.jtelemed.it",
"getreports"));
setRequestHeaders(_call);
setAttachments(_call);
try {
java.lang.Object _resp = _call.invoke(new
java.lang.Object[] {new java.lang.Integer(evt_id)});
if (_resp instanceof java.rmi.RemoteException) {
throw (java.rmi.RemoteException)_resp;
}
else {
extractAttachments(_call);
try {
- 204 -
APPENDICE - CODICE SORGENTE
return (java.lang.String) _resp;
} catch (java.lang.Exception _exception) {
return (java.lang.String)
org.apache.axis.utils.JavaUtils.convert(_resp,
java.lang.String.class);
}
}
} catch (org.apache.axis.AxisFault axisFaultException) {
throw axisFaultException;
}
}
public boolean uploadreport(int evt_id, int utn_id,
java.lang.String evt_content) throws
java.rmi.RemoteException {
if (super.cachedEndpoint == null) {
throw new
org.apache.axis.NoEndPointException();
}
org.apache.axis.client.Call _call = createCall();
_call.setOperation(_operations[6]);
_call.setUseSOAPAction(true);
_call.setSOAPActionURI("");
_call.setSOAPVersion(org.apache.axis.soap.SOAPConstants.SOA
P11_CONSTANTS);
_call.setOperationName(new
javax.xml.namespace.QName("http://services.jtelemed.it",
"uploadreport"));
setRequestHeaders(_call);
setAttachments(_call);
try {
java.lang.Object _resp = _call.invoke(new
java.lang.Object[] {new java.lang.Integer(evt_id), new
java.lang.Integer(utn_id), evt_content});
if (_resp instanceof java.rmi.RemoteException) {
throw (java.rmi.RemoteException)_resp;
}
else {
extractAttachments(_call);
try {
return ((java.lang.Boolean)
_resp).booleanValue();
} catch (java.lang.Exception _exception) {
return ((java.lang.Boolean)
org.apache.axis.utils.JavaUtils.convert(_resp,
boolean.class)).booleanValue();
}
}
- 205 -
APPENDICE - CODICE SORGENTE
} catch (org.apache.axis.AxisFault axisFaultException) {
throw axisFaultException;
}
}
public boolean invalidatereport(int evt_id, int
ref_ind) throws java.rmi.RemoteException {
if (super.cachedEndpoint == null) {
throw new
org.apache.axis.NoEndPointException();
}
org.apache.axis.client.Call _call = createCall();
_call.setOperation(_operations[7]);
_call.setUseSOAPAction(true);
_call.setSOAPActionURI("");
_call.setSOAPVersion(org.apache.axis.soap.SOAPConstants.SOA
P11_CONSTANTS);
_call.setOperationName(new
javax.xml.namespace.QName("http://services.jtelemed.it",
"invalidatereport"));
setRequestHeaders(_call);
setAttachments(_call);
try {
java.lang.Object _resp = _call.invoke(new
java.lang.Object[] {new java.lang.Integer(evt_id), new
java.lang.Integer(ref_ind)});
if (_resp instanceof java.rmi.RemoteException) {
throw (java.rmi.RemoteException)_resp;
}
else {
extractAttachments(_call);
try {
return ((java.lang.Boolean)
_resp).booleanValue();
} catch (java.lang.Exception _exception) {
return ((java.lang.Boolean)
org.apache.axis.utils.JavaUtils.convert(_resp,
boolean.class)).booleanValue();
}
}
} catch (org.apache.axis.AxisFault axisFaultException) {
throw axisFaultException;
}
}
}
- 206 -
APPENDICE - CODICE SORGENTE
A.3 COMMON LIBRARY
A.3.1
Certificate.java
package it.jtelemed.common;
import java.security.cert.X509Certificate;
import javax.servlet.http.HttpServletRequest;
public final class Certificate {
/**
* Ritorna l'elenco dei certificati X509 nella request
*
* @param request oggetto richiesta della Servlet
*
* @return elenco dei certificati X509
*/
public static X509Certificate[]
getX509Certificates(HttpServletRequest request) {
X509Certificate[] certs = null;
try {
if (request.isSecure())
{
if
(request.getAttribute("javax.servlet.request.X509Certificat
e") != null) {
// Leggo dagli attributi
dell'oggetto request
// l'elenco dei certificati
certs =
(java.security.cert.X509Certificate[])request.getAttribute(
"javax.servlet.request.X509Certificate");
}
}
}
catch (Exception ex) {
certs = null;
}
return certs;
}
/**
* Ritorna il certificato X509 i-esimo nella request
*
* @param request oggetto richiesta della Servlet
*
- 207 -
APPENDICE - CODICE SORGENTE
* @return certificato X509 i-esimo
*/
public static X509Certificate
getX509Certificate(HttpServletRequest request, int index) {
X509Certificate[] certs = null;
try {
certs = getX509Certificates(request);
if (certs != null && index > -1 && index <
certs.length)
return certs[index];
}
catch (Exception ex) {
}
return null;
}
/**
* Ritorna il SubjectDN del 1° certificato X509 nella
request
*
* @param request oggetto richiesta della Servlet
*
* @return elenco dei certificati X509
*/
public static java.security.Principal
getSubjectDN(HttpServletRequest request) {
java.security.Principal subjDN = null;
try {
X509Certificate[] certs =
getX509Certificates(request);
if (certs != null && certs.length > 0) {
subjDN = certs[0].getSubjectDN();
}
}
catch (Exception ex) {
subjDN = null;
}
return subjDN;
}
/**
* Estrae un campo dal un DistinguishName, ad es. CN
*
* @param certDN DistinguishName
* @param fieldDN Nome del Campo
*
- 208 -
APPENDICE - CODICE SORGENTE
* @return Valore del Campo
*
*/
public static String
extractDNField(java.security.Principal certDN, String
fieldDN) {
// dn_string contiene il DistinguishName
String dn_string = certDN.toString();
// dn_field_value conterrà il Valore del Campo,
ad es. Mirco Sturari
String dn_field_value = "";
// dn_fields[] contiene il DistinguishName
spezzato dalle virgole
String[] dn_fields = dn_string.split(",");
// dn_fields conterrà uno degli elementi di
dn_fields[]
String dn_field = "";
// dn_token conterrà il token dell'elemento
dn_field
String dn_token = "";
// se dn_fields[] non è null e contiene almeno un
elemento
if (dn_fields != null && dn_fields.length > 0) {
// Ciclo sugli elementi dell'array
dn_fields[]
for (int i = 0; i < dn_fields.length; ++i) {
// Leggo ciascuna stringa senza spazi a
destra e sinistra
dn_field = dn_fields[i].trim();
// Estraggo il Nome del Campo
dn_token = dn_field.substring(0,
dn_field.indexOf("=")).trim();
// Controllo che il Nome del Campo si
lo stesso cercato
if
(dn_token.compareToIgnoreCase(fieldDN) == 0) {
// Estraggo il Valore del Campo
dn_field_value =
dn_field.substring(dn_field.indexOf("=")+1);
// Esco dal ciclo
break;
}
}
}
// Ritorno il Valore del Campo
return dn_field_value;
}
- 209 -
APPENDICE - CODICE SORGENTE
/**
* Estrae il campo CountryCode(C) dal DistinguishName
*
* @param certDN DistinguishName
*
* @return CountryCode
*/
public static String
extractCountryCode(java.security.Principal certDN) {
// Estraggo il campo CountryCode
return extractDNField(certDN, "C");
}
/**
* Estrae il campo CommonName(CN) dal DistinguishName
*
* @param certDN DistinguishName
*
* @return CommonName
*/
public static String
extractCommonName(java.security.Principal certDN) {
// Estraggo il campo CommonName
return extractDNField(certDN, "CN");
}
/**
* Estrae il campo Email(E) dal DistinguishName
*
* @param certDN DistinguishName
*
* @return Email
*/
public static String
extractEmail(java.security.Principal certDN) {
// Estraggo il campo Email
return extractDNField(certDN, "EMAILADDRESS");
}
/**
* Estrae il campo Organization(O) dal DistinguishName
*
* @param certDN DistinguishName
*
* @return Organization
*/
public static String
extractOrganization(java.security.Principal certDN) {
// Estraggo il campo Organization
return extractDNField(certDN, "O");
- 210 -
APPENDICE - CODICE SORGENTE
}
/**
* Estrae il campo OrganizationUnit(OU) dal
DistinguishName
*
* @param certDN DistinguishName
*
* @return OrganizationUnit
*/
public static String
extractOrganizationUnit(java.security.Principal certDN) {
// Estraggo il campo OrganizationUnit
return extractDNField(certDN, "OU");
}
/**
* Un digest cifrato è quello in cui si usa
* una chiave segreta per creare il digest.
* Si possono usare chiavi diverse per creare
* differenti digest per lo stesso buffer di byte.
*
* @param algorithm algoritmo da usare per il digest
* @param buffer buffer di byte
* @param key chiave segreta per la cifratura
*
* @return digest
*/
public static byte[] getKeyedDigest(String algorithm,
byte[] buffer, byte[] key) {
try {
java.security.MessageDigest msgdg =
java.security.MessageDigest.getInstance(algorithm);
msgdg.update(buffer);
return msgdg.digest(key);
} catch (java.security.NoSuchAlgorithmException e)
{
}
return null;
}
/**
* Un digest cifrato è quello in cui si usa
* una chiave segreta per creare il digest.
* Si possono usare chiavi diverse per creare
* differenti digest per lo stesso file.
*
* @param algorithm algoritmo da usare per il digest
* @param path nome del file
* @param key chiave segreta per la cifratura
- 211 -
APPENDICE - CODICE SORGENTE
*
* @return digest
*/
public static byte[] getKeyedDigest(String algorithm,
String path, byte[] key) {
java.io.FileInputStream in;
try {
in = new java.io.FileInputStream(path);
int bytes = in.available();
byte[] buf = new byte[bytes];
in.read(buf, 0, buf.length);
in.close();
return getKeyedDigest(algorithm, buf, key);
} catch (Exception ex) {
}
return null;
}
/**
* Crea il digest a partire da un buffer.
*
* @param algorithm algoritmo da usare per il digest
* @param buffer buffer di byte
*
* @return digest
*/
public static byte[] getDigest(String algorithm,
byte[] buffer) {
try {
java.security.MessageDigest msgdg =
java.security.MessageDigest.getInstance(algorithm);
msgdg.update(buffer);
return msgdg.digest();
} catch (java.security.NoSuchAlgorithmException e)
{
}
return null;
}
/**
* Crea il digest a partire da un file.
*
* @param algorithm algoritmo da usare per il digest
* @param path nome del file
*
* @return digest
*/
public static byte[] getDigest(String algorithm,
String path) {
- 212 -
APPENDICE - CODICE SORGENTE
java.io.FileInputStream in;
try {
in = new java.io.FileInputStream(path);
int bytes = in.available();
byte[] buf = new byte[bytes];
in.read(buf, 0, buf.length);
in.close();
return getDigest(algorithm, buf);
} catch (Exception ex) {
}
return null;
}
}
A.3.2 Client.java
package it.jtelemed.common;
import javax.servlet.http.*;
public class Client {
public String user_name = "-";
public String user_kind = "-";
public int user_id = -1;
public String user_labwslink = "";
public String user_archivepath = "";
/**
* Costruttore pubblico che inizializza le proprietà
*
*/
public Client() {
user_id = -1;
user_name = "-";
user_kind = "-";
user_labwslink = "";
user_archivepath = "";
}
/**
* Metodo statico per la creazione di una istanza
della
* classe Client a partire da un oggetto di sessione
HTTP
*
* @param session oggetto di sessione HTTP
- 213 -
APPENDICE - CODICE SORGENTE
*
* @return istanza della classe Client
*/
public static Client create(HttpSession session) {
Client cli = new Client();
cli.user_id = new
Integer((String)session.getAttribute("USER_ID")).intValue()
;
cli.user_name =
(String)session.getAttribute("USER_NAME");
cli.user_kind =
(String)session.getAttribute("USER_KIND");
cli.user_labwslink =
(String)session.getAttribute("USER_LABWSLINK");
cli.user_archivepath =
(String)session.getAttribute("USER_ARCHIVEPATH");
return cli;
}
/**
* Metodo statico per il salvataggio di una classe
* Client all'interno di un oggetto di sessione HTTP
*
* @param cli istanza della classe Client
* @param session oggetto di sessione HTTP
*
*/
public static void save(Client cli, HttpSession
session) {
session.setAttribute("USER_ID",new
Integer(cli.user_id).toString());
session.setAttribute("USER_NAME",cli.user_name);
session.setAttribute("USER_KIND",cli.user_kind);
session.setAttribute("USER_LABWSLINK",cli.user_labwsli
nk);
session.setAttribute("USER_ARCHIVEPATH",cli.user_archi
vepath);
}
}
- 214 -
APPENDICE - CODICE SORGENTE
A.3.3 DateTime.java
package it.jtelemed.common;
import it.jtelemed.common.StringUtil;
public class DateTime {
/**
* Ritorna la data corrente
*
* @return restituisce la stringa contenente la data
corrente nel formato 'YYYY-MM-DD'
*/
public static String getCurrentDate() {
// Prendo un'istanza della classe Calendar
java.util.Calendar c =
java.util.Calendar.getInstance();
// Compongo la stringa contenente la data
String s = c.get(java.util.Calendar.YEAR) + "-" +
StringUtil.padString(new
Integer(c.get(java.util.Calendar.MONTH)+1).toString(),2,'0'
,true) + "-" +
StringUtil.padString(new
Integer(c.get(java.util.Calendar.DATE)).toString(),2,'0',tr
ue);
// Ritorno la stringa
return s;
}
/**
* Ritorna la data e l'ora corrente
*
* @return restituisce la stringa contenente la data e
l'ora corrente nel formato 'YYYY-MM-DD HH:MM:SS'
*/
public static String getCurrentDateTime() {
// Prendo un'istanza della classe Calendar
java.util.Calendar c =
java.util.Calendar.getInstance();
// Compongo la stringa contenente la data
String s = c.get(java.util.Calendar.YEAR) + "-" +
StringUtil.padString(new
Integer(c.get(java.util.Calendar.MONTH)+1).toString(),2,'0'
,true) + "-" +
StringUtil.padString(new
Integer(c.get(java.util.Calendar.DATE)).toString(),2,'0',tr
ue) + " " +
- 215 -
APPENDICE - CODICE SORGENTE
StringUtil.padString(new
Integer(c.get(java.util.Calendar.HOUR_OF_DAY)).toString(),2
,'0',true) + ":" +
StringUtil.padString(new
Integer(c.get(java.util.Calendar.MINUTE)).toString(),2,'0',
true) + ":" +
StringUtil.padString(new
Integer(c.get(java.util.Calendar.SECOND)).toString(),2,'0',
true);
// Ritorno la stringa
return s;
}
/**
* Ritorna il timestamp
*
* @param with_separator specifica se la stringa deve
contenere dei separatori
*
* @return restituisce la stringa contenente la data e
l'ora corrente nel formato 'YYYY-MM-DD HH:MM:SS MMMM'
*/
public static byte[] getTimeStamp(boolean
with_separator) {
// Prendo un'istanza della classe Calendar
java.util.Calendar c =
java.util.Calendar.getInstance();
StringBuilder sb = new StringBuilder();
// Compongo la stringa contenente la data
sb.append(c.get(java.util.Calendar.YEAR));
if (with_separator) sb.append("-");
sb.append(StringUtil.padString(new
Integer(c.get(java.util.Calendar.MONTH)+1).toString(),2,'0'
,true));
if (with_separator) sb.append("-");
sb.append(StringUtil.padString(new
Integer(c.get(java.util.Calendar.DATE)).toString(),2,'0',tr
ue));
if (with_separator) sb.append(" ");
sb.append(StringUtil.padString(new
Integer(c.get(java.util.Calendar.HOUR)).toString(),2,'0',tr
ue));
if (with_separator) sb.append(":");
sb.append(StringUtil.padString(new
Integer(c.get(java.util.Calendar.MINUTE)).toString(),2,'0',
true));
if (with_separator) sb.append(":");
- 216 -
APPENDICE - CODICE SORGENTE
sb.append(StringUtil.padString(new
Integer(c.get(java.util.Calendar.SECOND)).toString(),2,'0',
true));
if (with_separator) sb.append(" ");
sb.append(StringUtil.padString(new
Integer(c.get(java.util.Calendar.MILLISECOND)).toString(),2
,'4',true));
// Ritorno la stringa
return sb.toString().getBytes();
}
}
A.3.4 File Util.java
package it.jtelemed.common;
public class FileUtil {
/**
* Ritorna il nome del file senza il percorso
*
* @param path percorso completo del file
*
* @return nome del file senza il percorso
*/
public static synchronized String
extractFileName(String path) {
String s = "";
// Spezzo la stringa a partire dall'ultimo \
if (path.lastIndexOf("\\") > -1)
s =
path.substring(path.lastIndexOf("\\")+1);
// Spezzo la stringa a partire dall'ultimo /
else if (path.lastIndexOf("/") > -1)
s = path.substring(path.lastIndexOf("/")+1);
else
s = path;
// Ritorno la stringa
return s;
}
/**
* Ritorna l'estensione del file
*
* @param path percorso completo del file
- 217 -
APPENDICE - CODICE SORGENTE
*
* @return estensione del file
*/
public static synchronized String
extractFileExt(String path) {
String f = extractFileName(path);
String s = "";
// Spezzo la stringa a partire dall'ultimo .
if (f.lastIndexOf(".") > -1)
s = f.substring(f.lastIndexOf(".")+1);
return s;
}
/**
* Ritorna il nome del percorso con lo slash finale
*
* @param path percorso
*
* @return nome del percorso con lo slash finale
*/
public static synchronized String parsePathName(String
path) {
String s = "";
// Controllo che il percorso contenga \
if (path.lastIndexOf("\\") > -1) {
// Controllo che il percorso non finisca con
\
if (!path.endsWith("\\"))
s = path + "\\";
else
s = path;
}
// Controllo che il percorso contenga /
else if (path.lastIndexOf("/") > -1) {
// Controllo che il percorso non finisca con
/
if (!path.endsWith("/"))
s = path + "/";
else
s = path;
}
else
s = path + "/";
// Ritorno la stringa
return s;
}
/**
* Estrae un buffer contenente il file allegato
*
- 218 -
APPENDICE - CODICE SORGENTE
* @param att allegato al messaggio SOAP
*
* @return ritorna un buffer che contiene i byte letti
*/
public static byte[]
readFileBuffer(javax.xml.soap.AttachmentPart att) {
byte[] buffer = null;
try {
javax.activation.DataHandler dh =
att.getDataHandler();
if (dh != null) {
buffer =
readFileBuffer(dh.getInputStream());
}
} catch (Exception ex) {
buffer = null;
}
return buffer;
}
/**
* Estrae un buffer contenente il file allegato
*
* @param path nome del file
*
* @return ritorna un buffer che contiene i byte letti
*/
public static byte[] readFileBuffer(String path) {
byte[] buffer = null;
try {
buffer = readFileBuffer(new
java.io.FileInputStream(path));
} catch (Exception ex) {
buffer = null;
}
return buffer;
}
/**
* Estrae un buffer contenente il file allegato
*
* @param in file input strema
*
* @return ritorna un buffer che contiene i byte letti
*/
- 219 -
APPENDICE - CODICE SORGENTE
public static byte[]
readFileBuffer(java.io.InputStream in) {
byte[] buffer = null;
int bytes = 0;
try {
bytes = in.available();
if (bytes > 0) {
buffer = new byte[bytes];
in.read(buffer, 0, buffer.length);
}
} catch (Exception ex) {
bytes = -1;
}
return buffer;
}
/**
* Scrive il buffer nel file
*
* @param path nome del file da salvare
* @param buf byte da scrivere
*
* @return true se il file è stato salvato
*/
public static synchronized boolean
writeFileBuffer(String path, byte[] buf) {
boolean saved = false;
try {
if (buf != null) {
int bytes = buf.length;
if (bytes > 0) {
java.io.FileOutputStream out = new
java.io.FileOutputStream(path);
out.write(buf, 0, buf.length);
out.flush();
out.close();
saved = true;
}
}
} catch (Exception ex) {
saved = false;
}
return saved;
}
/**
- 220 -
APPENDICE - CODICE SORGENTE
* Scrive il log nel file
*
* @param path nome del file da salvare
* @param req richiesta da scrivere
*
* @return true se il file è stato salvato
*/
public static synchronized boolean logRequest(String
path, String req) {
boolean saved = false;
String row = DateTime.getCurrentDateTime() + "\t"
+ req + "\r";
try {
java.io.FileWriter out = new
java.io.FileWriter(path, true);
out.write(row);
out.flush();
out.close();
saved = true;
} catch (Exception ex) {
saved = false;
}
return saved;
}
/**
* Crea un file firmando un buffer di byte
*
* @param signed_name nome del file digest firmato e
serializzato
* @param uncript_buffer byte da firmare
*
* @return vero se il file firmato è stato creato
*/
public static synchronized boolean
createSignedFile(String signed_name, byte[] uncript_buffer)
{
try {
//
Creazione del digest
byte[]dig_buf = Certificate.getDigest("SHA1", uncript_buffer);
// Operazione di firma del digest e
serializzazione
it.jtelemed.smartcard.Firma firma = new
it.jtelemed.smartcard.Firma();
- 221 -
APPENDICE - CODICE SORGENTE
return firma.cifra(signed_name, dig_buf);
} catch (Exception ex) {
return false;
}
}
/**
* Verifica la firma del file
*
* @param report_name nome del file da verificare
* @param digest_name nome del digest con cui
verificare
*
* @return vero se la firma del file è verificata
*/
public static synchronized boolean
verifySignedFile(String report_name, String digest_name) {
try {
// Operazione di firma del digest e
serializzazione
it.jtelemed.smartcard.Firma firma = new
it.jtelemed.smartcard.Firma();
byte[] file_buff =
FileUtil.readFileBuffer(report_name);
byte[] digest_buff =
Certificate.getDigest("SHA-1", file_buff);
return firma.decifra(digest_name,
digest_buff);
} catch (Exception ex) {
return false;
}
}
/**
* Ritorna il nome di un file di evento
*
* @param prefix Prefisso del nome del file
* @param suffix Suffisso del nome del file
* @param evt_id Identificativo dell'evento
*
* @return (prefix)-(evt_id)(12).(suffix)
*/
public static synchronized String
getEventFileName(String prefix, String suffix, int evt_id)
{
- 222 -
APPENDICE - CODICE SORGENTE
return prefix + "-" +
StringUtil.padString(Integer.toString(evt_id),12,'0',true)
+ "." + suffix;
}
/**
* Ritorna il nome di un file di referto
*
* @param prefix Prefisso del nome del file
* @param suffix Suffisso del nome del file
* @param evt_id Identificativo dell'evento
* @param rep_ind Indice del referto
*
* @return (prefix)-(evt_id)(12)-(rep_ind)(3).(suffix)
*/
public static synchronized String
getReportFileName(String prefix, String suffix, int evt_id,
int rep_ind) {
return prefix + "-" +
StringUtil.padString(Integer.toString(evt_id),12,'0',true)
+ "-" + StringUtil.padString(new
Integer(rep_ind).toString(),3,'0',true) + "." + suffix;
}
}
- 223 -
BIBLIOGRAFIA
BIBLIOGRAFIA
Struttura di una applicazione web - Luca Balzerani
18/04/2002
L'ambiente di Tomcat - Massimo Vassalli
26/02/2002
Installazione di Apache Tomcat - Giuseppe Capodieci
13/03/2001
Java Server Pages, un'introduzione - Andrea De Paoli
10/07/2002
http://www.itportal.it/
http://www.weekit.it/
http://programmazione.html.it/
- 224 -
BIBLIOGRAFIA
[WSCA10] Heather Kreger, 2001, IBM, Web Services
Conceptual Architecture 1.0 .
[SOAP11]
W3C, Simple Object Access Protocol (SOAP)
1.1.
[WSDL11]
W3C,
Web
Services
Description
Language
(WSDL) 1.1 .
[UDDI-TWP] Uddi.org, UDDI Technical White Paper .
[FFP00]
J.Feghhi,
J.Fegghi,
P.Williams,
“Digital
Certificates Applied Internet Security”, Addison
Wesley, April 2000
[FJ03]
J.Falkner, K.Jones, “Servlets and JavaServer
Pages
:
The
J2EE
Technology
Web
Tier,
Addison Wesley, Sptember 2003
[C05]
C.Galasso, “Introduzione e … Jakarta Struts”,
Logica Informatica S.r.l., gennaio 2005
- 225 -
BIBLIOGRAFIA
[CBEGL04] V.Chopra, A.Bakore, J.Eaves, B. Galbraith,
S.Li, C.Wiggers, “Professional APACHE TOMCAT
5”, Wrox, May 2004
[C04]
C.Cavaness, “Programming Jakarta Struts, 2nd
Edition”, O’REILLY, April 2004
[CMV02]
P.Chandra,
M.Messier,
J.Viega,
“Network
Security with OpenSSL”, O’REILLY, June 2002
[F04]
N.Ford,
“Art
of
Java
Web
Development”,
Manning, July 2004
[RSA98]
“Frequently asked questions about today’s
cryptography”, RSA Laboratories, 1998.
[S90]
C.P.Schnorr,
signatures
“Efficient
for
smart
identification
cards”,
Advances
and
in
Cryptology, 1990
[RSA78]
R.L.Rivest, A.Shamir, L.Adleman, “A Method
for Obtaining Digital Signatures and Public-Key
Cryptosystem”, in “Communications of the
ACM”
- 226 -
BIBLIOGRAFIA
[RFC99]
C.Adams, S.Farrell, “Internet X.509 Public Key
Infrastructure
–
Certificate
Management
Protocols”, Marzo 1999
[RFAQ99]
“PCKS #11 Frequently Asked Question”, RSA
Laboratories, http://www.rsa.com
[MAM99]
M.Myers, R.Ankney, A.Malpani, S. Galperin,
C.Adams,
“X.509
Infrastructure
Internet
Online
Public
Certificate
Key
Status
Protocol – OCPS”, PKIX Working Group Draft,
Marzo 1999
[ITSEC]
Information
Tecnology
Security
Evaluation
Criteria, http://www.itsec.gov.uk
[V05]
I.Venuti,
“Guida
Pratica
WEB
SERVICES”,
Edizione Master, Novembre 2005
Java 2 Platform Standard Edition 5.0 Development Kit
(JDK) Update 5 jdk-1_5_0_05-windows-i586-p.exe
from http://java.sun.com/j2se/1.5.0/download.jsp
- 227 -
BIBLIOGRAFIA
Java 2 Platform Standard Edition 5.0 Documentation
From http://java.sun.com/j2se/1.5.0/download.jsp
Apache Tomcat 5.5.9 Binary jakarta-tomcat-5.5.9.exe from
http://jakarta.apache.org/site/downloads/
Lomboz 3.1 Release Candidate 2 lomboz-eclipse-emf-gef
from http://forge.objectweb.org/projects/lomboz
MySQL 4.1.14 Database Server mysql-4.1.14-win32.zip
from http://dev.mysql.com/downloads/mysql/4.1.html
MySQL
Java
Connector
3.0.17
mysql-connector-java-
3.0.17-ga.zip
from
http://dev.mysql.com/downloads/connector/j/3.0.html
Exadel
Studio
3.0.4
ExadelStudio-3.0.4.exe
from
http://www.exadel.com/products_exadelstudio.htm
OpenSSL
0.9.8a
Toolkit
openssl-0.9.8a.tar.gz
http://www.openssl.org/source/
- 228 -
from