Progettazione ed implementazione di un sistema di

Università degli Studi di Napoli Federico II
Facoltà di Scienze MM.FF.NN.
Corso di Laurea in Informatica
Tesi Sperimentale di Laurea Triennale
Progettazione ed implementazione di un sistema di
rappresentazione grafica di dati complessi
Relatori
Candidato
Prof. Guido Russo
Ing. Giovanni Battista Barone
Dott.ssa Vania Boccia
Anno accademico 2009/2010
Gianluca Coda
Matricola: 566/557
Indice generale
1 Introduzione.......................................................................................................................... 3
2 Modalità per la rappresentazione dei dati – relazioni fra entità, grafici semplici e grafici
complessi.....................................................................................................................................6
2.1 Tipi Di Relazioni Visualizzate Nei Diagrammi E Nei Grafici......................................6
2.2 Composizione Di Relazioni E Diagrammi Complessi................................................ 10
2.3 Rappresentazione Di Code E Flussi............................................................................ 11
3 Obiettivi e requisiti del sistema realizzato......................................................................... 14
3.1 Il Precedente Sistema Di Visualizzazione Del Centro CNAF.....................................17
3.2 Requisiti Funzionali Del Generatore Di Grafici .........................................................17
3.3 Requisiti Non Funzionali.............................................................................................20
3.4 Scelta Dei Tool - Confronto Tra Gnuplot E JFreeChart.............................................. 20
4 Specifica dei requisiti..........................................................................................................24
4.1 Use Case...................................................................................................................... 24
4.2 Tabelle Di Cockburn....................................................................................................25
5 Architettura del sistema di visualizzazione realizzato .......................................................42
5.1 Scomposizione Funzionale In Moduli.........................................................................42
5.1.1 Modulo di accesso dei dati job.......................................................................... 43
5.1.2 Modulo di trasformazioni dei file Job acquisiti ................................................44
5.1.3 Generazione di pagine JSP................................................................................ 48
5.2 Diagrammi UML Di Progettazione............................................................................. 53
5.2.1 Component Diagram..........................................................................................53
5.2.2 Class Diagram....................................................................................................54
5.2.3 Sequence Diagram............................................................................................. 56
6 Sviluppo dell'applicazione.................................................................................................. 57
6.1 Dal Diagramma Delle Classi Al Codice Java..............................................................57
6.2 Organizzazione Dei File Di Sistema Contenenti I Dati Dei Grafici...........................58
6.3 Libreria Di Visualizzazione JFreeChart ..................................................................... 59
6.4 Tipi Di Grafici............................................................................................................. 59
6.5 L'esportazione Verso Il Portale....................................................................................64
6.5.1 I formati immagini statici.................................................................................. 64
6.5.2 I formati immagini interattivi............................................................................ 66
6.5.3 Le scelte effettuate............................................................................................. 67
7 Conclusioni e futuri sviluppi...............................................................................................68
8 Bibliografia......................................................................................................................... 69
9 Appendici – Installazione e funzionamento del sistema.................................................... 70
9.1 Messa In Esercizio.......................................................................................................70
9.2 Guida D'uso................................................................................................................. 71
9.3 Codice Sorgente.......................................................................................................... 78
Gianluca Coda 566/557
Pagina 2 di 131
1 Introduzione
L'attività del tirocinio di tesi è stata svolta nell'ambito di un progetto in corso fra
l'Università di Napoli Federico II e il CNAF (Centro Nazionale per la Ricerca e
sviluppo per le tecnologie informatiche e telematiche) di Bologna.
L'attività della tesi ha riguardato lo studio, la progettazione e la realizzazione di un
generatore di grafici rappresentanti le attività dei sistemi di attesa (code) e dei job di
una Grid.
La prima fase dello stage è stata dedicata all'individuazione dei requisiti del generatore
di grafici. Tali requisiti sono stati ricercati con la chiara intenzione di superare alcuni
problemi esistenti in una precedente versione del visualizzatore e con le motivazioni di
estendere le funzionalità e le modalità di utilizzazione (suggerite in parte anche dai
gestori del sistema Grid). Per individuare tipi di visualizzazioni adeguate ai dati da
rappresentare si è intrapreso uno studio che è partito dall'analisi (astratta) di alcune
relazioni parte-totalità (ad esempio relazione fra una parte di un flusso e il flusso
totale), individuando successivamente il corrispondente tipo di grafico più adeguato al
tipo di relazione da rappresentare. L'analisi ha portato ad individuare l'adeguatezza di
un particolare diagramma per la rappresentazione di genesi di popolazioni di attese
(Virtual Organization, Gruppi e Code) in varie modalità di visualizzazione temporale
(per esempio rispetto ad un giorno, una settimana, un mese etc).
I requisti del generatore di grafici in parte funzionali (come quelli appena riportati) e in
parte non funzionali (come quelli relativi al tipo di codice di sviluppo) sono stati presi
come input, in una fase del tirocinio, dove si è progettato il visualizzatore, in
particolare sviluppando i diagrammi dei casi di uso, di classi e di sequenza per la
realizzazione del codice del programma. Il generatore di grafici è stato realizzato
secondo un'architettura riportata schematicamente nella figura 1.1.
Gianluca Coda 566/557
Pagina 3 di 131
Figura 1.1 - Schema di architettura e moduli del generatore grafico.
Dopo l'introduzione contenuta nel capitolo 1, nel capitolo 2 si è effettuato uno studio
per individuare, per ogni tipo di relazione parte-totalità, il tipo più adeguato di
diagramma da adottare per la visualizzazione. In tale capitolo si è individuata anche
una particolare rappresentazione grafica, la quale possiede caratteristiche di chiarezza
e di espressività per le attività complesse relative al monitoraggio delle code in un
Grid. Nel capitolo 3 sono stati individuati i requisiti funzionali e non funzionali del
generatore, in parte forniti da alcuni utenti (stakeholders) del Grid. Altri requisiti sono
stati individuati dal tirocinante. Nello stesso capitolo si è riportato anche uno studio dei
tool di base da adoperare per lo sviluppo del visualizzatore grafico. Nel capitolo 4
della tesi sono stati descritti i requisiti funzionali e non funzionali individuati durante
la fase iniziale del lavoro di tirocinio. Tali requisiti hanno costituito l'input per l'attività
di progettazione (contenuta nel capitolo 5) la quale è stata sviluppata applicando
metodi dell'ingegneria del software, utilizzando quindi gli standard diagrammi UML
dei casi d'uso, delle classi e delle sequenze. Nella tesi è contenuta una descrizione del
programma del generatore grafico realizzato (capitolo 6), nella quale viene riportato il
Gianluca Coda 566/557
Pagina 4 di 131
ruolo svolto da tutti i moduli software che compongono il sistema, in particolare è
stato descritto il modulo che rende possibile la visualizzazione dei grafici su WEB. In
tale parte di tesi sono stati forniti esempi di di funzionamento del visualizzatore
grafico. Nel capitolo 7 sono state riportate le conclusioni ed elencati i futuri sviluppi
del sistema, mentre la bibliografia è presente nel capitolo 8. Infine, in appendice è
stato riportato il codice Java sviluppato relativo ai principali moduli del sistema. Per le
finalità di utilizzazione del sistema realizzato, è stata redatta una guida di installazione
e di utilizzazione del sistema di visualizzazione realizzato.
Gianluca Coda 566/557
Pagina 5 di 131
2 Modalità per la rappresentazione dei dati – relazioni fra entità, grafici
semplici e grafici complessi
In questo capitolo, partendo dall'analisi di alcune relazioni di parte e totalità, si è
individuato una corrispondenza tra un insieme di relazioni parte/totalità presenti nel
dominio dei dati da visualizzare e un insieme di grafici più adeguati per la loro
rappresentazione. Nello stesso capitolo sono state individuate alcune specifiche
modalità di rappresentazione per dati complessi (diagrammi genetici) che meglio
esprimono le relazioni di entità del dominio della rappresentazione delle attese,
oggetto di studio di questo tirocinio.
2.1 Tipi di relazioni visualizzate nei diagrammi e nei grafici
I sistemi di visualizzazione di grafici hanno nelle loro funzionalità di base quelle di
disegnare valori di proprietà o di caratteristiche fisiche di oggetti, o insiemi, nello
spazio e nel tempo. La maggior parte dei layout esistenti nei sistemi software
predisposti per questo scopo (ad esempio Excel, MatLab) assumono come
rappresentazione di una totalità, uno spazio-3d, un piano, un cerchio etc, e le parti in
tali spazi geometrici.
Esistono diverse ricerche dove sono state studiate le relazioni fra parti e totalità.
Winston, Chaffin e Hermann (1987) hanno proposto le relazioni chiamate WCH
(acronimo dei nomi degli ideatori). Abbiamo preso come riferimento queste relazioni
per individuare un insieme di relazioni di base a partire dalle quali costruire grafici più
complessi.
Riportiamo un insieme di tipologie di relazioni parti e totalità, di interesse al dominio
Gianluca Coda 566/557
Pagina 6 di 131
dei sistemi di attese, e i corrispondenti grafici.
Relazioni componente/oggetto - sono relazioni tra oggetti composti (totalità) e le loro
parti, dove le parti sono separabili ed hanno una loro funzionalità, per esempio
manico/tazza, tastiera/computer, tasti/tastiera, etc (diagramma dei componenti UML).
Le relazioni componente/oggetto vengono in genere visualizzate in un spazio
bidimensionale attraverso icone o simboli (che rappresentano le componenti o parti
della totalità) che (quasi sempre) non rispecchiano le reali distanze (neppure in scala)
fra le componenti. Nel dominio delle Grid un esempio di tale relazione componente
oggetto e il diagramma corrispondente è il seguente:
Figura 2.1.1 – Esempio di relazione parte-totalità di tipo componente-oggetto
(elementi e servizi della European DataGrid).
Relazioni membro/collezione – sono relazioni che stabiliscono un'appartenenza di un
elemento ad una collezione. I membri non hanno un ruolo funzionale nella collezione e
possono essere pertanto separati. Costituiscono un esempio di tali relazioni
albero/foresta, cella di memoria/MemoriaRam, etc. Anche queste relazioni vengono
rappresentate in forma iconica come nel caso precedente.
Gianluca Coda 566/557
Pagina 7 di 131
Figura 2.1.2 - Esempio di relazione parte-totalità di tipo membro-collezione.
Relazioni porzione/totalità – stabiliscono una relazione fra una parte o porzione della
totalità costituita dallo stesso materiale della totalità e la totalità stessa. Esempi di tali
relazioni sono fetta/torta, tipo_persona/popolazione. Rientrano in questo gruppo
code/flussi_totali tipici per la rappresentazione di attività di calcolo di un computer
eseguite e quelle ancora da eseguire in un certo intervallo temporale. Le relazioni
porzione/totalità sono rappresentate attraverso i tipici diagramma a torta.
Figura 2.1.3 – Esempio di relazione parte-totalità di tipo porzione-totalità
Gianluca Coda 566/557
Pagina 8 di 131
Relazioni materiale/oggetto - sono relazioni tra un oggetto o una componente di esso
e il tipo di materiale di cui è costituito. In questo caso il materiale non può essere
separato dall’oggetto, non una ha funzionalità e non è omogeneo. Per esempio
acciaio/telaio_bici. In questa categoria appartiene una classe di relazione
tipo_regione/regione. I diagrammi tipici che vengono adoperati per la visualizzazione
di queste relazioni, sono quelli delle mappe tematiche dove aree di un territorio come
case, strade, linee ferroviarie etc, vengono visualizzate con una trama diversa in un
diagramma. I rapporti spaziali fra parti e totalità in questi diagrammi sono mantenuti
attraverso opportune scale e sistemi di riferimento.
Figura 2.1.4 - Esempio di relazione parte-totalità di tipo materiale-oggetto.
Relazioni caratteristica/attività – sono relazioni che descrivono una caratteristica di
un'attività, evento o fenomeno complesso. Le caratteristiche sono rappresentate spesso
nel tempo, hanno un ruolo funzionale, ma non sono separabili dall'attività. Rientrano
in questa categoria i diagrammi che descrivono un'attività complessa attraverso un
insieme di caratteristiche (temperature, densità, fasi etc) che variano nel tempo.
Gianluca Coda 566/557
Pagina 9 di 131
Figura 2.1.5 -Esempio di relazione parte-totalità di tipo caratteristica-attività
2.2 Composizione di relazioni e diagrammi complessi
Le relazioni presentate costituiscono una serie di relazioni base a partire dalle quali si
costruiscono più complesse relazioni. Ad esempio una relazione materiale-oggetto che
varia nel tempo (è il caso di una mappa tematica GIS che varia nel tempo), oppure
come la sovrapposizione di relazioni caratteristiche di una relazione caratteristica
-attività.
Queste relazioni complesse creano alcune difficoltà nella costruzione dei relativi
diagrammi. Per per la costruzione di diagrammi in cui ci sono sovrapposizione di
relazioni di caratteristiche/attività come ad esempio gli stati di più job (più
caratteristiche) in esecuzione in un centro di calcolo (attività del centro), occorre ad
risolvere il problema di quanti job al massimo rappresentare e come distinguere
graficamente i vari job al fine di ottenere grafici di migliore lettura per gli utenti. Un
esempio di diagramma di caratteristiche sovrapposte è rappresentato nella seguente
figura.
Gianluca Coda 566/557
Pagina 10 di 131
Figura 2.2.1 – Esempio di diagramma con caratteristiche sovrapposte.
Alcuni diagrammi complessi utilizzati in questa tesi sono stati quelli di genesi di
popolazioni o alberi genetici (diretti o inversi). I quali risultano essere costituiti da una
composizione di relazioni porzioni-totalità, dove ogni porzione (omogenea alla
totalità) può a sua volta essere composto da altre porzioni (sempre contenenti elementi
dello stesso tipo della totalità).
2.3 Rappresentazione di code e flussi
Le code e flussi sono entità che sono presenti in varie scenari di attività umane o di
sistemi industriali o informatici. Esistono diversi sistemi di visualizzazione di code e
di flussi, utilizzati a tal punto da costituire una sorta di metafora per diversi scenari
anche molto differenti tra loro.
Tipici sistemi (e metafore) di gestione di code sono:
•i clienti in una banca o un ufficio postale in attesa di un'operazione da eseguire;
•le persone in coda in attesa di un taxi;
Gianluca Coda 566/557
Pagina 11 di 131
•i veicoli in attesa di un ingresso ad un casella stradale;
•gli aerei in attesa di decollo o di atterraggi;
•sistemi di elaborazione;
•sistemi di comunicazione / trasmissione dati;
•sistemi di lavorazione industriale.
Tutti questi scenari hanno in comune:
A)una popolazione in ingresso di potenziali clienti;
B)delle tipologie di clienti che si qualificano per tipo di servizio;
C)un insieme di code;
D)un insieme di servitori di servizi associate alle code.
B e C differiscono l'uno dall'altro poiché presentano differenti strutture. Ad esempio un
ufficio postale può avere una gerarchia di servizi (si veda figura 2.3.1) e diversi
servitori ossia differenti sportelli che compiono il servizio.
Figura 2.3.1 - Ufficio postale - gerarchia di servizi.
Gianluca Coda 566/557
Pagina 12 di 131
Le rappresentazioni di flussi e di strutture di attese possono essere rappresentati come
un albero genetico costituiti da un insieme di popolazioni Pi, un insieme di relazioni di
tipo insieme sott'insieme R: R(Px,Py) con x≠y e un insieme di caratteristiche Cn
associate ad ogni Pi.
La rappresentazione di tali alberi genetici è realizzata attraverso diagrammi del tipo
riportato in figura 2.3.2.
Figura 2.3.2 – Rappresentazione di code come gerarchie
di popolazione o alberi genetici
Tali diagrammi sono dello stesso tipo proposti in questa tesi per la rappresentazioni dei
job di un sistema Grid, ma possono essere utilizzati in ogni sistema di attesa,
specificando di volta in volta la popolazione Px (inserita nella tassonomia) e una
caratteristiche Cn (in funzione di qualche variabile) associate a tale popolazione.
Gianluca Coda 566/557
Pagina 13 di 131
3 Obiettivi e requisiti del sistema realizzato
Abbiamo già riportato che l'attività del tirocinio di tesi è stata svolta nell'ambito di un
progetto in corso fra l'Università di Napoli Federico II e il CNAF (Centro Nazionale
per la Ricerca e sviluppo per le tecnologie informatiche e telematiche) di Bologna.
Il CNAF si occupa della gestione e dello sviluppo a livello nazionale dei principali
servizi informatici e telematici di supporto all'INFN. Tale centro partecipa da alcuni
anni allo sviluppo, implementazione e gestione di infrastrutture di “Griglia” a livello
italiano (GRID.it) e internazionali (EGEE e LHC Computing GRID) - per i quali è
curato anche parte della progettazione e dello sviluppo.
Lo sviluppo del generatore di grafici realizzato in questo tirocinio rientra tra le attività
del CNAF. Esso costituirà il sistema di visualizzazione dei grafici per rappresentare i
flussi dei dati presenti nel Grid su indicato. Tra gli obiettivi del sistema vi è anche
quello di rappresentare i dati di monitoraggio in tempo reale e secondo serie storiche,
adottando diverse strategie di aggregazione sia per i dati che per le entità del Grid.
Le principali entità del sistema Grid possono essere espresse/rappresentate tramite il
seguente diagramma di classi UML.
Figura 3.1 – Esempio di parti della Grid e sue relazioni.
Gianluca Coda 566/557
Pagina 14 di 131
Dall'immagine si possono individuare le relazioni fra le entità della Grid di cui ne sono
state monitorate le attività. Nella Grid sono presenti una o più Code. Ogni Coda è
identificata da una stringa e può usufruire di determinate risorse per lo svolgimento di
un compito. Ad ogni Coda sono associati gruppi di utenti, in maniera diretta o tramite
aggregazioni (astratte) denominate VO (Virtual Organization). Ogni VO è anch'essa
identificata per mezzo di una stringa. Un Utente rappresenta il soggetto che ha la
possibilità di interagire con la griglia sfruttandone le capacità di calcolo. Tale processo
viene attivato mediante sottomissione dei Job alla Grid. Un Job indica una sequenza di
compiti (di istruzioni di calcolo) che impegnano le risorse della Grid e possono, nel
tempo, trovarsi in diversi stati (in attesa, sospesi etc) - quest'ultimi hanno una
denominazione specifica a seconda dello scheduler (politica di pianificazione) adottato
dalla Grid. Nell'ambito della sperimentazione del lavoro di tesi, gli scheduler
considerati sono di due tipi: PBF e LSF.
Nel PBF i job possono avere i seguenti stati:
Nome Stato
Descrizione
S (suspended)
Indica lo stato in cui è un job sospeso dal server dove
rimarrà in questa condizione fino a che non ci saranno
risorse libere per l'esecuzione
Q (queued)
Questo stato indica i job in coda, quest'ultimi possono
essere in seguito eseguiti o assegnati ad atre risorse
W (waiting)
Indica un job in attesa di esecuzione. In questo stato sono
inclusi anche i job la cui richiesta è fallita per qualche
motivo
R (running)
Indica un Job in esecuzione
E (exited)
Indica un job terminato con successo e costituisce lo
stato successivo all'esecuzione
T (transiction)
Indica un job in transazione per una nuova locazione
Tabella 3.1
Gianluca Coda 566/557
Pagina 15 di 131
Nello scheduler LSF invece, gli stati sono:
Nome Stato
Descrizione
PSUSP
Indica un job sospeso dal proprietario oppure un job
sospeso dallo Scheduler mentre era nello stato PEND
SSUSP
Indica un job sospeso dal sistema
PEND
Indica un job in coda
POST_DONE
Post processo senza errori
POST_EXIT
Post processo con errori
WAIT
Indica lo stato in cui si trova un job in attesa di essere
eseguito
EXITED
Indica un job che è terminato con uno stato di errore
DONE
Indica un job terminato con successo
UNKWN
Stato sconosciuto, costuisce una conseguenza della
perdita di collegamento tra il demone Mbatchd ed il
sbattchd dell'host
ZOMBI
Indica lo stato in cui un job non è più eseguibile in
quanto ucciso; solitamente si effettua un'operazione di
kill su un job in stato UNKWN.
Un'altra possibilità per la quale un job si trovi in questo
stato, è dovuta all'indisponibilità dell'host in cui avrebbe
dovuto essere eseguito il job; in questo caso il job verrà
ucciso ed il suo stato successivo sarà EXITED
RUN
Indica lo stato di un job che in esecuzione
Tabella 3.2
Gianluca Coda 566/557
Pagina 16 di 131
3.1 Il precedente sistema di visualizzazione del centro CNAF
Il sistema di visualizzazione delle attività del Grid (d'ora in avanti indicato con SPVG)
esistente, presentava manchevolezze e inadeguatezze di funzionalità che riportiamo nei
seguenti punti:
A)SPVG si limita a fornire delle immagini in formato compresso (png) che sono
prodotte da uno script interpretabile da Gnuplot, il quale fornisce una rappresentazione
ad istogrammi che non riesce a rappresentare i flussi di dati con una risoluzione
accettabile;
B)SPVG presenta una seconda tipologia di grafici, relativi ad altri aspetti delle attività
della Grid, realizzati in Flash, che per questa data tecnologia software si prevedono
problemi di incompatibilità di supporto dei futuri browser Internet;
C)SPVG aveva la funzionalità di effettuare zoom (aumento di dettaglio) sia per
intervallo di tempo, sia per tipo di attività;
D)Non è esiste una funzionalità in SPVG per la visualizzazione di un albero genetico
delle popolazioni, per cui non è possibile conosce l'appartenenza di un certo
sottogruppo al gruppo che lo ha generato;
E)Il punto D implica anche che SPVG prevede solo un livello di gerarchia fra gruppi
cioè solo i livelli VO-code;
F)SPVG prevede solo una corrispondenza di uno ad uno fra VO e code.
3.2 Requisiti funzionali del generatore di grafici
In questo paragrafo riportiamo i requisiti funzionali per il generatore di grafici forniti
dai coordinatori di Grid.it, in parte determinati attraverso interviste del tirocinante a
quest'ultimi.
Gianluca Coda 566/557
Pagina 17 di 131
Dall'analisi è scaturito che uno degli obiettivi del sistema è quello di generare dei
grafici di monitoraggio a partire dai dati provenienti dallo scheduler del sistema Grid,
che superassero tutte le anomalie ed inadempienze individuate (si veda paragrafo
precedente) in particolare implementando una funzionalità di visualizzazione dei dati
mediante una rappresentazione ad alberi genetici diretti (si veda figura 2.3.2) e inversi.
Altro requisito, inoltre, è quello di fornire a richiesta una rappresentazione globale dei
job in esecuzione.
Tra i requisiti funzionali si è individuato quello della visualizzazione in Web
dell'attività del Grid.
Nella tabella 3.2.1 si riporta l'elenco dei requisiti funzionali individuati:
Requisito funzionale
Descrizione
Visualizzazione grafica dei dati storici Possibilità
di
visualizzare
mediante
rappresentazione
grafica
i
dati
di
monitoraggio della Grid nei seguenti
intervalli temporali:
•giornaliero;
•settimanale;
•mensile;
•annuale.
Visualizzazione
tabellare
monitoraggio della Grid
del Possibilità di visualizzare in forma tabellare i
dati di monitoraggio della Grid in tempo
reale.
Navigazione basata su alberi genetici
Gianluca Coda 566/557
Menu strutturati rappresentati mediante
alberi genetici. In particolare per la
visualizzazione grafica dei dati storici, sono
stati richiesti i seguenti menu:
•albero genetico - rispecchia la struttura
della Grid, a 3 livelli di profondità. Le voci
di primo livello si riferiscono alle Code,
quelle di secondo livello alle VO ed infine
quelle di terzo livello ai Gruppi. Le
Pagina 18 di 131
informazioni accessibili tramite questo menu
sono una rappresentazione grafica dei dati
forniti dal Parser. Non vengono forniti dal
Parser i dati del livello VO per il quale si
costruisce una rappresentazione dei dati
concatenando i dati dei suoi sottolivelli
(Gruppi).
•albero genetico inverso- questo menu ha 2
livelli di profondità. Le voci di primo livello
si riferiscono alle VO, mentre le voci di
secondo livello alle Code. Al livello delle VO
si ha una rappresentazione dei dati forniti dal
Parser, mentre per il livello delle Code si
costruisce una rappresentazione mediante
concatenazione dei dati del livello superiore
(VO).
Per la visualizzazione tabellare di
monitoraggio è stato richiesto il seguente
menu:
•albero genetico ridotto- ha 2 livelli di
profondità e rispecchia la struttura della Grid.
Dove al primo livello si ha una
rappresentazione delle Code ed al secondo
livello una rappresentazione delle VO.
Interfaccia via web
Possibilità di utilizzare l'interfaccia utente
attraverso il Web.
Salvataggio grafici
Possibilità
di
archiviazione
delle
rappresentazioni grafiche dei dati in locale.
Interattività dei grafici
Gianluca Coda 566/557
Possibilità di effettuare zoom su porzioni
arbitrarie dei grafici.
Tabella 3.2.1
Pagina 19 di 131
3.3 Requisiti non funzionali
I requisiti non funzionali per l'implementazione del generatore dei grafici che
riguardano la tipologia dei file in ingresso, non costituiscono dei vincoli per gli
strumenti di sviluppo adoperati, essendo i formati dei file del sistema di provenienza
compatibili con la maggior parte dei sistemi.
E' stato richiesto che l'interfaccia di visualizzazione del generatore fosse compatibile
con i sistemi operativi Windows e Linux.
Tra i requisiti non funzionali del nuovo visualizzatore è emerso quello relativo alla
possibilità di esportare i grafici in vari formati e di offrire un certo grado di
interattività. Inoltre si è scelto di sviluppare il sistema grafico di visualizzazione in
ambiente Java, al fine di evitare eventuali problemi di installazione di software di terze
parti e di non incorrere ad altre eventuali incompatibilità con qualche tipologia di
browser. Si è ritenuto infine che la scelta Java, come piattaforma software di sviluppo,
potesse risolvere eventuali problemi di integrazione e di compatibilità con gli altri
moduli collegati al funzionamento di monitoraggio della Grid.
Infine, tra i requisiti non funzionali è stato scelto di generare i layout di interfaccia in
Inglese.
3.4 Scelta dei tool - confronto tra Gnuplot e JFreeChart
Dopo aver individuato i requisiti del generatore di grafici è emersa la necessità di
scegliere un sistema o una libreria grafica come di sviluppo del visualizzatore. La
scelta è ricaduta su due tool, molto usati per questi tipi di applicazioni: Gnuplot e
JfreeChart. Il primo si è posto all'attenzione perché era il tool usato per la generazione
dei grafici del precedente sistema (SPVG), il secondo, invece, preso in considerazione
Gianluca Coda 566/557
Pagina 20 di 131
per una migliore adeguatezza alla metodologia di sviluppo basata su JAVA. Si è quindi
passati ad una comparazione fra questi due strumenti di sviluppo.
Gnuplot, inizialmente sviluppato intorno al 1986, rivolto alla rappresentazione di dati
scientifici con i seguenti formati (Latex, PostScript, fig, metafont), oggi è in grado di
essere utilizzato da vari linguaggi di programmazione, tra cui: AWK, C, C++, Java,
Python, Perl e Visual Basic. Gnuplot è un programma open source, che consente di
realizzare grafici sia in 2D che in 3D, accettando in ingresso vari formati di
rappresentazione di dati. Disponibile per vari sistemi operativi, è utilizzato attraverso
comandi o script non troppo complessi, inviati al terminale di visualizzazione.
Consente di ottenere diversi output: a video, stampanti, esportazione nei più comuni
formati di immagini, etc. Esempi di grafici ottenuti da Gnuplot sono del tipo:
Figura 3.4.1 – Esempi di grafici Gnuplot.
Gianluca Coda 566/557
Pagina 21 di 131
JFreeChart è una libreria Java, anch'essa Open Source, che può essere integrata sia in
applicazioni Java locali che in applicazioni web. Possiede una gran varietà di tipi di
rappresentazione di dati, dai più comuni grafici a “torta”, a “istogrammi” sino a
grafici complessi come “time series chart” o “Gantt”.
La scelta di utilizzare JFreeChart, rispetto a Gnuplot, oltre alla compatibilità di base
Java, è motivata dalle seguenti osservazioni:
–possibilità di generare grafici complessi sia 2D che 3D;
–permette il salvataggio in vari formati quali JPEG, PNG, PDF, SVG (tramite Batik);
–possibilità di visualizzare, mediante puntamento mouse sul grafico,
valori dei
diagrammi (conosciuta anche come una funzionalità di tipo tooltip) ;
–permette zoom interattivo
Esistono due entità che si possono definire in JFreeChart: i Dataset e le Series. I
Dataset sono collezioni di Series, queste ultime costituite da strutture che
immagazzinano i dati da rappresentare. Esistono vari tipi di Dataset e Series in base
alla natura dei dati da monitorare. Sono disponibili Dataset che consentono
l'importazione di dati da Database e file di testo.
Un altro aspetto interessante di JFreeChart è la gestione degli eventi che consente di
realizzare grafici interattivi. A tal fine è possibile utilizzare tooltip per la gestione degli
eventi legati all'uso del mouse.
I principali passi da seguire per la generazione di un grafico con JFreeChart sono:
•
creazione di un Dataset in base al tipo di grafico;
•
popolamento del Dataset per mezzo di oggetti Series in base alla natura dei dati;
•
creazione di un oggetto JFreeChart con il Dataset precedentemente creato.
Alcune personalizzazioni del grafico possono prevedere:
• l'inserimento di attributi del grafico tramite una delle classi del package plot;
Gianluca Coda 566/557
Pagina 22 di 131
• un rendering del grafico tramite una delle classi del package renderer;
• l'inserimento di assi del grafico tramite una delle classi del package axis.
Si riportano di seguito alcuni esempi di grafici ottenuti da JFreeChart:
Figura 3.4.2 – Esempio di grafici con JFreeChart.
Gianluca Coda 566/557
Pagina 23 di 131
4 Specifica dei requisiti
Per il superamento delle inadeguatezze A), B), C), D) e E) (individuate in 3.1)
dell'esistente visualizzatore sono state proposte alcune nuove funzionalità e soluzioni
implementative, che riporteremo in questo capitolo.
Rispetto ai requisiti stabiliti dai responsabili del Grid, sono stati inseriti alcune
funzionalità di visualizzazione aggiuntive come input alla progettazione del
visualizzatore (requisiti funzionali). Esse sono state scelte:
–per migliorare la leggibilità da parte dell'utente nel raggruppare grafici di interesse di
tutte le entità relative alle attese/code del Grid;
–per visualizzare particolari relazioni fra code/attese e Job utilizzando un albero
genetico;
–per consentire di effettuare uno zoom su particolare intervalli di tempo o su uno
specifico dato di interesse non ben evidenziato dal scala corrente attivata;
–per consentire di avere più rappresentazioni grafiche (caratteristiche) per uno stesso
insieme di dati;
–per consentire di esportare in diversi formati i grafici generati.
Riportiamo gli use case in formato UML dei requisiti appena elencati.
4.1 Use Case
Figura 4.1.1 – Alcuni casi d'uso del Sistema di Visualizzazione.
Gianluca Coda 566/557
Pagina 24 di 131
Dal caso d'uso riportato in figura 4.1.1 si evincono le principali funzionalità del
sistema. Il caso d'uso “visualizza monitoraggio” consente ad un generico utente di
conoscere in tempo reale i dati di esercizio della Grid. “visualizza storici” consente,
invece, di osservare l'andamento dei dati di esercizio della Grid nel tempo. In questo
caso, l'utente ha la possibilità di scegliere vari tipi di rappresentazione dei dati
(“modifica tipo menu”) e di salvare i grafici in vari formati (“salva storico”).
Per quanto riguarda il caso d'uso “visualizza storici” si riporta un use case diagram che
offre un maggior livello di dettaglio:
Figura 4.1.2 – Casi d'uso – Funzioni di monitoraggio.
4.2 Tabelle di Cockburn
Use case#1
visualizza storici
Obiettivo del Use case
L'utente desidera visualizzare gli storici di
esercizio della Grid
Precondizioni
Nessuna
Condizione d'uscita con successo
L'utente ha correttamente visualizzato le
informazioni di suo interesse
Gianluca Coda 566/557
Pagina 25 di 131
Condizione d'uscita con insuccesso
L'utente non ha ottenute le informazioni
richieste
Attori partecipanti
Utente (Attore primario)
Trigger (azione di avvio)
L'utente accede all'interfaccia web
Descrizione
Step n°
Utente
1
Accede
all'interfaccia web
Estensione 1:
interfaccia irraggiungibile
Sistema
2
Mostra il
menu di
navigazione
basato
sull'albero
genetico
della Grid
2.1
In caso di
irraggiungibi
lità
dell'interfacc
ia web,
mostra un
errore
esplicativo
Use case#2
visualizza grafici giornalieri
Obiettivo del Use case
L'utente desidera visualizzare gli storici
giornalieri di esercizio della Grid
Precondizioni
L'utente
ha
effettuato
l'accesso
all'interfaccia di visualizzazione degli
storici della Grid (Use case#1)
Condizione d'uscita con successo
L'utente ha correttamente visualizzato gli
storici giornalieri di suo interesse
Condizione d'uscita con insuccesso
L'utente non ha ottenute le informazioni
richieste
Gianluca Coda 566/557
Pagina 26 di 131
Attori partecipanti
Utente (Attore primario)
Trigger (azione di avvio)
L'utente seleziona dal menu principale la
voce “giornalieri”
Descrizione
Step n°
Utente
1
Seleziona dal
menu principale
la voce
“giornalieri”
Sistema
2
Mostra
l'elenco della
struttura di
genesi della
Grid e il
grafico dei
dati
giornalieri
totali
Estensione 1:
interfaccia irraggiungibile
2.1
In caso di
irraggiungibi
lità
dell'interfacc
ia web,
mostra un
errore
esplicativo
Estensione 2:
Caricamento grafico non riuscito
2.1
Il sistema
non è in
grado di
caricare il
grafico (ad
esempio:
plugin applet
Java
mancante sul
brower
dell'utente),
quindi
mostra un
Gianluca Coda 566/557
Pagina 27 di 131
errore
esplicativo
Superordinates
•Use case#1 (visualizzazione grafica)
Use case#3
visualizza grafici settimanali
Obiettivo del Use case
L'utente desidera visualizzare gli storici
settimanali di esercizio della Grid
Precondizioni
L'utente
ha
effettuato
l'accesso
all'interfaccia di visualizzazione degli
storici della Grid (Use case#1)
Condizione d'uscita con successo
L'utente ha correttamente visualizzato gli
storici settimanali di suo interesse
Condizione d'uscita con insuccesso
L'utente non ha ottenute le informazioni
richieste
Attori partecipanti
Utente (Attore primario)
Trigger (azione di avvio)
L'utente seleziona dal menu principale la
voce “settimanali”
Descrizione
Step n°
Utente
1
Seleziona dal
menu principale
la voce
“settimanali”
Estensione 1:
Gianluca Coda 566/557
Sistema
2
Mostra
l'elenco della
struttura di
genesi della
Grid e il
grafico dei
dati
settimanali
totali
2.1
In caso di
Pagina 28 di 131
interfaccia irraggiungibile
Estensione 2:
Caricamento grafico non riuscito
irraggiungibi
lità
dell'interfacc
ia web,
mostra un
errore
esplicativo
2.1
Il sistema
non è in
grado di
caricare il
grafico (ad
esempio:
plugin applet
Java
mancante sul
brower
dell'utente),
quindi
mostra un
errore
esplicativo
Superordinates
•Use case#1 (visualizzazione grafica)
Use case#4
visualizza grafici mensili
Obiettivo del Use case
L'utente desidera visualizzare gli storici
mensili di esercizio della Grid
Precondizioni
L'utente
ha
effettuato
l'accesso
all'interfaccia di visualizzazione degli
storici della Grid (Use case#1)
Condizione d'uscita con successo
L'utente ha correttamente visualizzato gli
storici mensili di suo interesse
Condizione d'uscita con insuccesso
L'utente non ha ottenute le informazioni
richieste
Gianluca Coda 566/557
Pagina 29 di 131
Attori partecipanti
Utente (Attore primario)
Trigger (azione di avvio)
L'utente seleziona dal menu principale la
voce “mensili”
Descrizione
Step n°
Utente
1
Seleziona dal
menu principale
la voce “mensili”
Sistema
2
Mostra
l'elenco della
struttura di
genesi della
Grid e il
grafico dei
dati mensili
totali
Estensione 1:
interfaccia irraggiungibile
2.1
In caso di
irraggiungibi
lità
dell'interfacc
ia web,
mostra un
errore
esplicativo
Estensione 2:
Caricamento grafico non riuscito
2.1
Il sistema
non è in
grado di
caricare il
grafico (ad
esempio:
plugin applet
Java
mancante sul
brower
dell'utente),
quindi
mostra un
errore
esplicativo
Gianluca Coda 566/557
Pagina 30 di 131
Superordinates
•Use case#1 (visualizzazione grafica)
Use case#5
visualizza grafici annuali
Obiettivo del Use case
L'utente desidera visualizzare gli storici
annuali di esercizio della Grid
Precondizioni
L'utente
ha
effettuato
l'accesso
all'interfaccia di visualizzazione degli
storici della Grid (Use case#1)
Condizione d'uscita con successo
L'utente ha correttamente visualizzato gli
storici annuali di suo interesse
Condizione d'uscita con insuccesso
L'utente non ha ottenute le informazioni
richieste
Attori partecipanti
Utente (Attore primario)
Trigger (azione di avvio)
L'utente seleziona dal menu principale la
voce “annuali”
Descrizione
Step n°
Utente
1
Seleziona dal
menu principale
la voce “annuali”
Estensione 1:
interfaccia irraggiungibile
Gianluca Coda 566/557
Sistema
2
Mostra
l'elenco della
struttura di
genesi della
Grid e il
grafico dei
dati annuali
totali
2.1
In caso di
irraggiungibi
lità
dell'interfacc
ia web,
mostra un
Pagina 31 di 131
errore
esplicativo
2.1
Estensione 2:
Caricamento grafico non riuscito
Il sistema
non è in
grado di
caricare il
grafico (ad
esempio:
plugin applet
Java
mancante sul
brower
dell'utente),
quindi
mostra un
errore
esplicativo
Superordinates
•Use case#1 (visualizzazione grafica)
Use case#6
Cambia tipo menu
Obiettivo del Use case
L'utente desidera cambiare il tipo di menu
Extend
•Use case#1 (visualizzazione grafica)
Precondizioni
L'utente
ha
effettuato
l'accesso
all'interfaccia di visualizzazione degli
storici della Grid (Use case#1)
Condizione d'uscita con successo
L'utente ha correttamente cambiato il tipo
di menu
Condizione d'uscita con insuccesso
-
Attori partecipanti
Utente (Attore primario)
Trigger (azione di avvio)
L'utente seleziona
inverso”
Descrizione
Step n°
Gianluca Coda 566/557
Utente
la
voce
“albero
Sistema
Pagina 32 di 131
1
Seleziona la voce
“albero inverso”
2
Mostra il
menu
strutturato
secondo
l'albero
genetico
inverso
Use case#7
Salvataggio immagine
Obiettivo del Use case
L'utente desidera salvare l'immagine del
grafico attualmente visualizzato
Extend
•Use case#1 (visualizzazione grafica)
Precondizioni
L'utente
ha
effettuato
l'accesso
all'interfaccia di visualizzazione degli
storici della Grid (Use case#1)
Condizione d'uscita con successo
L'utente ha correttamente salvato il
grafico
Condizione d'uscita con insuccesso
L'utente non riesce a salvarel'immagine
Attori partecipanti
Utente (Attore primario)
Trigger (azione di avvio)
L'utente seleziona una voce del menu per
visualizzare uno storico
Descrizione
Step n°
Utente
1
Seleziona una
voce del menu per
visualizzare uno
storico
2
Gianluca Coda 566/557
Sistema
Mostra il
grafico
relativo allo
storico
selezionato
dall'utente
Pagina 33 di 131
con i bottoni
per il
salvataggio
dell'immagin
e in vari
formati
3
Preme su uno dei
bottoni per
salvare
l'immagine nel
formato
desiderato
4
5
Estensione1:
Caricamento grafico non riuscito
Use case#8
Gianluca Coda 566/557
Mostra il
grafico nel
formato
scelto
L'utente salva
l'immagine
2.1
Il sistema
non è in
grado di
caricare il
grafico (ad
esempio:
plugin applet
Java
mancante sul
brower
dell'utente),
quindi
mostra un
errore
esplicativo
Visualizza grafico coda
Pagina 34 di 131
Obiettivo del Use case
L'utente desidera visualizzare il grafico
relativo ad una coda attiva sulla Grid
Extend
•Use case#1 (visualizzazione grafica)
Precondizioni
L'utente
ha
effettuato
l'accesso
all'interfaccia di visualizzazione degli
storici della Grid (Use case#1) e
selezionato una delle voci relative agli
intervalli
temporali
(giornalieri,
settimanali, mensili, annuali)
Condizione d'uscita con successo
L'utente ha correttamente visualizzato il
grafico relativo alla coda ed intervallo
temporale selezionati
Condizione d'uscita con insuccesso
L'utente non è riuscito a visualizzare il
grafico atteso
Attori partecipanti
Utente (Attore primario)
Trigger (azione di avvio)
L'utente seleziona dal menu principale il
nome della coda desiderata
Descrizione
Step n°
Utente
1
Seleziona dal
menu principale il
nome della coda
desiderata
Estensione 1:
Caricamento grafico non riuscito
Gianluca Coda 566/557
Sistema
2
Mostra il
grafico
relativo alla
coda ed
all'intervallo
temporale
selezionati
2.1
Il sistema
non è in
grado di
caricare il
grafico (ad
esempio:
plugin applet
Java
Pagina 35 di 131
mancante sul
brower
dell'utente),
quindi
mostra un
errore
esplicativo
Use case#9
Visualizza grafico VO
Obiettivo del Use case
L'utente desidera visualizzare il grafico
relativo ad una VO attiva sulla Grid
Extend
•Use case#1 (visualizzazione grafica)
Precondizioni
L'utente
ha
effettuato
l'accesso
all'interfaccia di visualizzazione degli
storici della Grid (Use case#1),
selezionato una delle voci relative agli
intervalli
temporali
(giornalieri,
settimanali, mensili, annuali) e della coda
di suo interesse
Condizione d'uscita con successo
L'utente ha correttamente visualizzato il
grafico relativo alla VO ed intervallo
temporale selezionati
Condizione d'uscita con insuccesso
L'utente non è riuscito a visualizzare il
grafico atteso
Attori partecipanti
Utente (Attore primario)
Trigger (azione di avvio)
L'utente seleziona dal menu principale il
nome della VO desiderata
Descrizione
Step n°
Utente
1
Seleziona dal
menu principale il
nome della VO
desiderata
2
Gianluca Coda 566/557
Sistema
Mostra il
grafico
Pagina 36 di 131
relativo alla
VO ed
all'intervallo
temporale
selezionati
Estensione 1:
Caricamento grafico non riuscito
2.1
Il sistema
non è in
grado di
caricare il
grafico (ad
esempio:
plugin applet
Java
mancante sul
brower
dell'utente),
quindi
mostra un
errore
esplicativo
Use case#10
Visualizza grafico other
Obiettivo del Use case
L'utente desidera visualizzare il grafico
relativo ai gruppi, non appartenenti a
nessuna VO, attivi sulla Grid
Extend
•Use case#1 (visualizzazione grafica)
Precondizioni
L'utente
ha
effettuato
l'accesso
all'interfaccia di visualizzazione degli
storici della Grid (Use case#1),
selezionato una delle voci relative agli
intervalli
temporali
(giornalieri,
settimanali, mensili, annuali) e della coda
di suo interesse
Condizione d'uscita con successo
L'utente ha correttamente visualizzato il
grafico relativo ai gruppi non appartenenti
Gianluca Coda 566/557
Pagina 37 di 131
a nessuna VO ed intervallo temporale
selezionati
Condizione d'uscita con insuccesso
L'utente non è riuscito a visualizzare il
grafico atteso
Attori partecipanti
Utente (Attore primario)
Trigger (azione di avvio)
L'utente seleziona dal menu principale il
nome della coda desiderata
Descrizione
Step n°
Utente
1
Seleziona dal
menu principale
la voce “other”
Estensione 1:
Caricamento grafico non riuscito
Gianluca Coda 566/557
Sistema
2
Mostra il
grafico
relativo a
tutti i gruppi
non
appartenenti
a nessuna
VO
relativament
e ad una
specifica
coda ed
all'intervallo
temporale
selezionati
2.1
Il sistema
non è in
grado di
caricare il
grafico (ad
esempio:
plugin applet
Java
mancante sul
brower
dell'utente),
quindi
Pagina 38 di 131
mostra un
errore
esplicativo
Use case#11
Visualizza grafico gruppo
Obiettivo del Use case
L'utente desidera visualizzare il grafico
relativo ad un gruppo attivo sulla Grid
Extend
•Use case#1 (visualizzazione grafica)
Precondizioni
L'utente
ha
effettuato
l'accesso
all'interfaccia di visualizzazione degli
storici della Grid (Use case#1),
selezionato una delle voci relative agli
intervalli
temporali
(giornalieri,
settimanali, mensili, annuali), della coda e
della VO di suo interesse
Condizione d'uscita con successo
L'utente ha correttamente visualizzato il
grafico relativo al gruppo ed intervallo
temporale selezionati
Condizione d'uscita con insuccesso
L'utente non è riuscito a visualizzare il
grafico atteso
Attori partecipanti
Utente (Attore primario)
Trigger (azione di avvio)
L'utente seleziona dal menu principale il
nome della coda desiderata
Descrizione
Step n°
Utente
1
Seleziona dal
menu principale il
nome del gruppo
desiderato
2
Gianluca Coda 566/557
Sistema
Mostra il
grafico
relativo al
gruppo ed
Pagina 39 di 131
all'intervallo
temporale
selezionati
Estensione 1:
Caricamento grafico non riuscito
2.1
Il sistema
non è in
grado di
caricare il
grafico (ad
esempio:
plugin applet
Java
mancante sul
brower
dell'utente),
quindi
mostra un
errore
esplicativo
Use case#12
Visualizza monitoraggio
Obiettivo del Use case
L'utente desidera visualizzare i dati
relativi ai job in esecuzione in quel
momento sulla Grid
Precondizioni
Nessuna
Condizione d'uscita con successo
L'utente ha correttamente visualizzato le
informazioni di suo interesse
Condizione d'uscita con insuccesso
L'utente non ha ottenuto le informazioni
richieste
Attori partecipanti
Utente (Attore primario)
Trigger (azione di avvio)
L'utente accede all'interfaccia web
Descrizione
Step n°
Utente
1
Accede
all'interfaccia web
Gianluca Coda 566/557
Sistema
Pagina 40 di 131
2
3
Mostra il
menu di
navigazione
basato
sull'albero
genetico
della Grid
L'utente seleziona
una voce dal
menu principale
4
Estensione 1:
interfaccia irraggiungibile
Gianluca Coda 566/557
2.1
In caso di
irraggiungibi
lità
dell'interfacc
ia web,
mostra un
errore
esplicativo
Pagina 41 di 131
5 Architettura del sistema di visualizzazione realizzato
5.1 Scomposizione funzionale in moduli
Il sistema di visualizzazione è stato realizzato scomponendo le funzionalità individuate
in sottofunzionalità e associando quest'ultime a moduli software separati (si veda a tale
riguardo lo schema di architettura riportato in figura 5.1.1).
Figura 5.1.1 – Schema dell'architettura del Sistema di Visualizzazione.
Gianluca Coda 566/557
Pagina 42 di 131
5.1.1 Modulo di accesso dei dati job
Nei file ASCII, forniti dall'output del PARSER (un programma responsabile della
produzione dei file job in un stabilito formato), sono presenti organizzati in colonne (si
veda tabella 5.1.1.1). Il contenuto di tali file ha la seguente struttura:
Data
Etichetta 1
…
Etichetta n
Valore data 1
X1,1
X1,..
X1,n
…
...
...
Valore data m
Xm,1
Xm,... Xm,n
Tabella 5.1.1.1
dove Xi,j, con i che va da 1 ad m e j che va da 1 a n, si riferisce alla j-esima etichetta al tempo
i-esimo.
Sul primo rigo sono presenti i nomi delle colonne che, ad eccezione della prima,
rappresentano gli “stati” che i job assumono.
Nella prima colonna vi sono le date cui si riferiscono i dati delle colonne successive.
Il modulo di accesso dei dati job ha la responsabilità di effettuare, ad intervalli di
tempo regolari, il caricamento in memoria dei dati riguardanti i job. In particolare il
modulo è costituito da un insieme di thread che periodicamente leggono i file ASCII.
Ogni thread del modulo in esame è responsabile delle letture di tutti i file di dati di uno
specifico intervallo temporale. Attualmente sono previsti i seguenti intervalli
temporali:
•giornaliero
•settimanale
•mensile
•annuale
Gianluca Coda 566/557
Pagina 43 di 131
5.1.2 Modulo di trasformazioni dei file Job acquisiti
Per ogni entità della Grid viene prodotto un file contenente le informazioni dello stato
dell'entità. Nasce quindi, in molti casi, l'esigenza di integrare in una unica struttura dati
(un unico file di archivio) tutti i dati.
Il processo di trasformazione dei file job acquisiti è affidato a due specifici processi
(thread):
•ConcatenatoreGruppi;
•ConcatenatoreVO.
Lo scopo dei thread è leggere i file di loro interesse e, come suggerisce il nome,
concatenarne i dati. I file ottenuti dal processo di concatenazione rispettano la struttura
precedentemente descritta nella tabella 5.1.1.1. In particolare il processo di
concatenazione avviene ordinando in una sequenza etichettata tutte le colonne presente
nei singoli file.
Nelle immagini a seguire si riporta il processo di concatenazione di tre file (File A,
File B e File C). L'unico vincolo nel formato dei file per una corretta concatenazione
riguarda il numero di righe e di colonne che deve essere lo stesso per tutti i file. In tale
contesto, tale vincolo non costituisce un problema in quanto le informazioni di
monitoraggio della Grid sono standardizzate sia dal punto di vista temporale (la
colonna Data per ogni file è uguale) che di tipi di informazioni (tutti i file hanno ugual
numero di colonne).
Gianluca Coda 566/557
Pagina 44 di 131
Figura 5.1.2.1 – Esempio di funzionamento del modulo di concatenazione.
I nuovi nomi delle etichette sono generate per mezzo di concatenazione dei nomi dei
file e delle relative etichette (<NuovaEtichetta>= <NomeFile>_<Etichetta>). Questa
operazione è fondamentale per assegnare in maniera univoca i nomi delle nuove
etichette. Nella figura a seguire è riportato un esempio che crea il nuovo nome della
colonna mediante concatenazione appena descritta.
Gianluca Coda 566/557
Pagina 45 di 131
Figura 5.1.2.2 – Schema concatenazione dei nomi delle etichette.
Con tale scelta di rappresentazione è possibile ottenere senza ambiguità digrammi di
visualizzazione del tipo riportato nella figura che segue.
Figura 5.1.2.3 – Esempio di rappresentazione ad istogrammi.
L'utilità di rappresentare i dati in tal modo immagazzinati, consiste nel fatto che a
partire da tale rappresentazione si può generare un grafico più dettagliato rispetto a
quello totale.
Consideriamo l'andamento di un grafico che indica il numero di persone presenti in
Gianluca Coda 566/557
Pagina 46 di 131
una sala cinematografica durante cinque giorni di proiezione. Una prima
rappresentazione di tale scenario può essere del tipo riportato in figura 5.2.1.4. a) (di
colore arancio).
Se si è interessati a conoscere la distribuzione del numero di uomini e donne si può
rappresentare la situazione distinguendo i dati per ogni categoria di persone (grafici di
colore blu e rosso). Con la scelta appena riportata è possibile ricostruire il grafico
totale delle persone (figura 5.2.1.4. b) riportando anche la distinzione degli insiemi
delle parti (uomini e donne). La tecnica adottata in questa tesi è stata quella di ottenere
la rappresentazione della totalità (ad esempio delle persone) aggregando i dati relativi
delle parti (uomini e donne nella figura 5.2.1.4. b).
Figura 5.2.1.4 – Rappresentazioni di gruppi in scenari complessi.
Gianluca Coda 566/557
Pagina 47 di 131
5.1.3 Generazione di pagine JSP
Per sito dinamico si intende un sito che pur mantenendo le stesse funzionalità (ad
esempio una modalità di presentazione dei dati di un'interfaccia) può fornire un
contenuto di dati variabili che è determinato in genere da un aggiornamento di un data
base di riferimento che subisce un aggiornamento. Per implementare il tipo
di
dinamicità appena descritto, sono stati creati dei sistemi per automatizzare i processi di
comunicazione tra un richiedente che possiede una modalità di presentazione (client) e
un sistema che fornisce la risposta alla richiesta (server). Le tecnologie Server Side
CGI (Common Gateway Interface) non sono prese da noi in considerazione per i loro
riconosciuti svantaggi come ad esempio un eccessivo peso sul processore ed attività
computazionali di produzione di output a carico del sistema. Entrambi gli svantaggi
appena elencati rappresentavano un problema che non poteva essere sottovalutato
sopratutto per applicazioni Web-Oriented che possono incorrere in un elevato numero
di interrogazioni.
La Sun Microsystem con la creazione delle Servlet è riuscita a risolvere i problemi
delle applicazioni CGI. Tale tecnologia è stata quella da noi adottata nel sistema di
visualizzazione realizzato. Ne riportiamo la descrizione delle entità di base di questa
tecnologia.
Le Servlet sono delle classi realizzate in Java dotate di una definita struttura e sono
richiamate al solo scopo di generare i contenuti dinamicamente. Uno dei principali
vantaggi delle Servlet è che il carico di lavoro che prima era affidato al processore ora
passa al Servelt Engine, programma caricato in memoria che si occupa della gestione
dei processi generati dalle richieste degli utenti. Un particolare Servlet Engine è
Tomcat, denominato anche Servlet Container o Servlet/JSP. Tomcat può essere inteso
anche come un Web Server, come ad esempio Apache, perché riesce sia ad interpretare
le richieste inviate dai client, sia a provvede alla generazione dinamica dei dati.
Gianluca Coda 566/557
Pagina 48 di 131
Rispetto ad Apache, Tomcat offre alcune caratteristiche aggiuntive che descriveremo
più avanti in questo paragrafo.
La politica di gestione degli input/output di Tomcat non è molto differente da quella
adottata da un qualsiasi Web Server. Dopo l'inserimento e l'acquisizione del url,
vengono visualizzate alcune strutture che esistono già al momento dell'attivazione di
Tomcat. Queste strutture prendono il nome di Contesto, le quali sono controllate da
oggetti che sono attivi sia nel loro ambito di azione che per gli utenti che vi accedono.
Il Web Server assegna ad ogni utente un Contenitore che è chiamato Sessione che
contiene le risorse disponibili per uno specifico utente. Tramite questa Sessione
l'utente ha la possibilità di inviare le richieste per la generazione dinamica dell'output.
Anche le richieste possono essere intese come dei Contenitori che hanno un ciclo di
vita che ha una durata che va dall'inizio della richiesta sino al tempo del suo
soddisfacimento.
Per quanto riguarda i metodi di gestione degli input/output invece Tomcat è
caratterizzato dall'istanza di un particolare oggetto chiamato Request (in sigla Req) che
viene lanciato nel momento in cui si inserisce l'url. In conseguenza dell'istanza di Req
viene istanziato, dal Servlet Engine, un altro oggetto chiamato Response( in sigla Res).
Entrambi gli oggetti saranno inviati al Contesto (inteso come oggetto) per soddisfare la
richiesta del client. Infine, un ulteriore oggetto è istanziato da Tomcat, di nome Ses. Il
ruolo di tale oggetto è di identificare in maniera univoca l'utente e di verificare che la
sua Sessione sia attiva. Gli esiti di tali operazioni possono essere:
•la Servlet ha esaudito la richiesta e delega Tomcat per la consegna dell'output al
client;
•la risorsa necessaria per soddisfare la richiesta non è disponibile presso il Contesto
utilizzato quindi Tomcat ha il compito di riavviare la procedura per cercare la risorsa
in altri Contesti;
•la richiesta può essere soddisfatta nel Contesto, ma tramite un'altra risorsa si crea un
Gianluca Coda 566/557
Pagina 49 di 131
Forward verso la giusta risorsa.
La scelta della tecnologia JSP ha consentito di ottenere un'interfaccia utente
raggiungibile via Web dove i contenuti vengono generati dinamicamente.
Il diagramma a seguire mostra l'architettura del livello di presentazione adottato,
conosciuto come Model 1 (approccio introdotto dalle specifiche JSP 0.92).
TOMCAT
File
System
BROWSER
JSP
Data
Base
Figura 5.1.3.1 – Ruolo JSP/Tomcat nella visualizzazione web.
Con questa soluzione le pagine JSP svolgono il seguente ruolo:
•l'utente, interagendo con il Browser, richiede una pagina JSP;
•il codice contenuto nella JSP richiesta esegue operazioni di controllo ed accesso ai
dati;
•la pagina JSP genera l'output HTML e lo invia al Browser.
Le JSP contengono, in particolare, codice HTML per i contenuti statici e codice JAVA
per la generazione di contenuti HTML dinamici; hanno quindi la responsabilità di
gestione del flusso di controllo e di presentazione dei dati.
Nel caso in esame, per la generazione dei dati dinamici, le JSP accedono ad un
Database ed al file system del server che le ospita.
Prevedendo sviluppi futuri del visualizzatore è stato scelto di strutturare le JSP
Gianluca Coda 566/557
Pagina 50 di 131
secondo una scomposizione basata sugli scopi. Una generica pagina HTML ha la
seguente struttura:
HTML
INTESTAZIONE
MENU
i-Frame centrale
Figura 5.1.3.2 – Regioni del layout del Sistema di Visualizzazione.
I componenti costituenti la pagina Web sono i seguenti:
•INTESTAZIONE:
contenuto statico, presente in tutte le schermate dell'applicazione, che costituisce
l'intestazione delle pagine;
•MENU:
menu generato dinamicamente. Consente di navigare nella struttura dati delle
informazioni (alberi genetici) da rappresentare. Nel contesto in esame tale struttura
replica una porzione del file system contenente i dati di monitoraggio. Allo stato
attuale sono presenti due menu distinti che offrono due tipologie di viste della struttura
dati.
◦Il primo menu, denominato “Albero genetico” …......,
◦il secondo, “Albero inverso”, ........
•i-Frame centrale:
porzione centrale in cui, alla selezione di una voce del Menu, viene visualizzata, in
Gianluca Coda 566/557
Pagina 51 di 131
maniera dinamica, una rappresentazione delle informazioni relative alla voce
selezionata.
Riportiamo una schermata di esempio dell'applicazione realizzata.
Figura 5.1.3.3 – Esempio di visualizzazione del sistema realizzato.
Come si può osservare nell'interfaccia viene segnato in rosso l'intestazione statica, in
verde il menu dinamico e, in giallo, l'area riservata al frame centrale.
Gianluca Coda 566/557
Pagina 52 di 131
5.2 Diagrammi UML di progettazione
5.2.1 Component Diagram
Figura 5.2.1.1 – Esempio di rappresentazione del diagramma delle componenti.
Gianluca Coda 566/557
Pagina 53 di 131
5.2.2 Class Diagram
L'intera applicazione realizzata risiede all'interno di un pacchetto denominato
“qjmon”:
Figura 5.2.2.1 – Package qjmon contenente l'intera applicazione realizzata.
Il pacchetto “qjmon” contiene una classe Configuratore che ha la responsabilità di
eseguire i thread dell'applicazione realizzata. È presente inoltre un pacchetto,
“viewer”, che contiene il cuore dell'applicazione realizzata.
Figura 5.2.2.2 – Contenuto del package qjmon.
Gianluca Coda 566/557
Pagina 54 di 131
Si riporta di seguito il contenuto del pacchetto “viewer” con la descrizione delle
responsabilità di ogni classe:
Figura 5.2.2.3 – Diagramma delle classi.
Nome
Tipo
Responsabilità
Concatenatore
Classe Astratta
Generico Thread che si occupa della
concatenazione dei dati.
ConcatenatoreGruppi Classe
Thread che ha la responsabilità
concatenare i file dei dati dei gruppi.
di
ConcatenatoreVO
Classe
Thread che ha la responsabilità
concatenare i file dei dati delle VO.
di
GeneratoreGrafici
Classe
Thread che, periodicamente, genera una
lista di grafici.
Grafico
Classe
Rappresenta un grafico.
Per maggiori dettagli si rimanda alla documentazione JavaDoc allegata in formato
elettronico al presente lavoro di tesi.
Gianluca Coda 566/557
Pagina 55 di 131
5.2.3 Sequence Diagram
Sequenza di operazione eseguite dal configuratore per avviare i Thread della
applicazione realizzata.
Tale sequenza viene eseguita per ogni intervallo temporale.
Figura5. 2.3.1 – Diagramma di sequenza.
Gianluca Coda 566/557
Pagina 56 di 131
6 Sviluppo dell'applicazione
In questo paragrafo riportiamo la descrizione degli aspetti implementativi del
generatore di grafici realizzato. I moduli software che sono stati realizzati rispecchiano
la progettazione effettuata (riportata in diagrammi UML nel paragrafo precedente).
L'intero sistema è stato sviluppato in JAVA, avvalendosi per la parte della generazione
dei grafici, della libreria JFreeChart.
6.1 Dal diagramma delle classi al codice Java
Nei diagrammi di progettazione UML sono presenti le seguenti classi:
–ConcatenatoreGruppi.java
–ConcatenatoreVO.java
–Configuratore.java
–GeneratoreGrafici.java
–Grafico.java
La classe ConcatenatoreGruppi.java si occupa della generazione del file contenente i
dati relativi a tutti i gruppi appartenenti ad una stessa VO.
ConcatenatoreVO.java funziona in maniera simile alla precedente ma relativamente
all'albero di genesi inverso, in pratica concatena tutti i file di una determinata VO
presenti su tutte le code.
La classe Configuratore.java è quella che contiene i metodi che avviano i thread, tali
thread sono 3 per ogni “intervallo di tempo” di dati (giornalieri, settimanali etc etc), i
funzionamento due Concatenatori è stato già spiegato.
Gianluca Coda 566/557
Pagina 57 di 131
GeneratoreGrafici.java è responsabile della generazione di un classe di grafici.
Grafico.java è il cuore dell'applicazione, quella che implementa i metodi ed utilizza le
librerie di JFreeChart.
6.2 Organizzazione dei file di sistema contenenti i dati dei grafici
I dati riguardanti i job sono memorizzati su file ASCII (leggibili con qualsiasi editor di
testo). Tali file sono memorizzati in un insieme di file di sistema (cartelle) che hanno
una radice comune chiamata “struttura/”. Le cartelle prossime alla radice sono 4, le
quali rappresentano gli intervalli di tempo di validità delle caratteristiche delle code:
giorno, settimana, mese ed anno. Ogni sottocartella a partire da tali 4 cartelle
rappresenta un insieme relativo ad una coda, organizzazione virtuale, gruppo.
Figura 6.2.1 – Organizzazione del File System.
Gianluca Coda 566/557
Pagina 58 di 131
6.3 Libreria di visualizzazione JFreeChart
Il modulo designato alla generazione dei grafici per mezzo della libreria JFreeChart è
costituito dalle classi:
•GeneratoreGrafici
•Grafico
GeneratoreGrafici ha la responsabilità di generare un insieme di grafici. In particolare
vi sono 4 possibili insiemi:
•giornalieri
•settimanali
•mensili
•annuali
per ognuno di questi è responsabile un thread GeneratoreGrafici che, per mezzo della
classe Grafico, a partire dai file dei dati, genera i relativi grafici.
La classe Grafico a partire da un file di dati genera il relativo grafico nei seguenti
formati: PNG, JPEG, PDF e SVG. In tali grafici i valori delle ascisse rispecchiano i
valori della prima colonna del file (cioè la data) mentre le ordinate rappresentano i
valori dei relativi stati. Le etichette delle legende dei grafici sono ricavate a partire
dalle intestazioni dei file.
6.4 Tipi di grafici
Il Sistema realizzato prevede tre tipi di plot per la rappresentazione dei dati di
monitoraggio della Grid, denominati:
Gianluca Coda 566/557
Pagina 59 di 131
1.a linee;
2.a curve stacked (impilate o a pila);
3.ibrido.
Tutte le tipologie sono rappresentazioni nel piano cartesiano e prevedono l'uso di un
colore univoco per ogni dato rappresentato al variare del tempo. L'asse delle ordinate
ha come unità di misura il Job, mentre l'asse delle ascisse rappresenta intervalli di
tempo (di osservazione) (figura 6.4.1: solo gli assi con le unità di misura senza dati).
Figura 6.4.1 – Esempio di rappresentazione degli assi.
Nel primo tipo di rappresentazione, a linee, i dati monitorati vengono rappresentati
come spezzate i cui estremi sono due punti di osservazione consecutivi (figura 6.4.2:
esempio di rappresentazione solo a linee).
Gianluca Coda 566/557
Pagina 60 di 131
Figura 6.4.2 – Esempio di rappresentazione dei dai mediante rappresentazione a linee.
In questo tipo di grafico potrebbero presentarsi problemi di sovrapposizione delle linee
(dati con valori che si discostano di poco gli uni dagli altri, figura 6.4.3: esempio di
diagramma a linee con valori sovrapposti) che comprometterebbero l'utilità stessa
della rappresentazione.
Figura 6.4.3 – Esempio di rappresentazione di dati per mezzo di linee.
Gianluca Coda 566/557
Pagina 61 di 131
Il secondo tipo di rappresentazione, a curve impilate, prevede che i valori di un dato,
nel tempo, vengono rappresentati tramite spezzate i cui estremi sono coppie
consecutive di punti di osservazione. L'area sottesa dalle spezzate viene inoltre
colorata in maniera univoca (figura 6.4.4: diagramma stacked con una sola area
rappresentata).
Figura 6.4.4 – Esempio di rappresentazione dei dati mediante aree.
Una caratteristica importante di questa rappresentazione è il concetto di “curve
impilate”. Questo concetto può essere espresso nel seguente modo:
Siano
da C1 a Ck le k curve stacked rappresentate in un grafico;
C i={x 1 , .. , x n }
i
i
con i=1,... , k ,
n i la cardinalità dell'insieme delle osservazioni dell'i-esima curva,
x j , con
i
Gianluca Coda 566/557
j=1,... , n , la j-esima osservazione dell'i-esima curva.
Pagina 62 di 131
La rappresentazione a curve stacked, prevede che la generica osservazione x j
i
della
curva Ci , sia rappresentata dal punto A= j , x j x j  .
i
i−1
In altri termini i valori di ogni curva vengono sommati ai corrispondenti (relativamente
al tempo) valori della curva precedente.
In figura 6.4.5 viene riportato un esempio di due curve stacked. È da notare che i
valori della seconda curva sono ottenuti come somma dei valori della prima e della
seconda.
Figura 6.4.5 – Esempio di rappresentazione di più dati mediante aree impilate.
Questo tipo di rappresentazione rimedia ai problemi di sovrapposizione della
rappresentazione a linee, consentendo di valutare in maniera intuitiva gli andamenti di
un dato in rapporto agli altri.
L'ultima modalità è la “ibrida” (o mix) che, come suggerisce il nome, unisce le due
precedenti modalità fornendo un più rapido strumento di monitoraggio e ne migliora la
leggibilità in quanto possono essere rappresentate curve che indicano soglie
interessanti (come ad esempio totali, disponibili) in modalità “linea” e quindi di lettura
Gianluca Coda 566/557
Pagina 63 di 131
immediata mentre tutte le altre curve con la modalità “curve”. In questo modo si ha
anche il vantaggio di non produrre grafici troppo dispersivi.
Nell'esempio in figura 6.4.6 è possibile osservare un grafico che utilizza sia linee che
aree per la rappresentazione dei dati (esempio di grafico ibrido).
Figura 6.4.6 – Esempio di rappresentazione combinata dei dati.
6.5 L'esportazione verso il portale
Tomcat, jsp, scelta dei contenuti statici/ non statici, aggiornamento grafici.
6.5.1 I formati immagini statici
PNG, acronimo di Portable Network Graphics, è un particolare formato compresso di
immagini, nato intorno al 1995, e di lì a poco approvato dal W3C (World Wide Web
Consortium), per fronteggiare la richiesta di pagamento, per l'utilizzo in programmi,
da parte dei detentori del brevetto di un altro formato molto diffuso in quel periodo, la
GIF. La sua estensione è .png.
Gianluca Coda 566/557
Pagina 64 di 131
Il PNG immagazzina immagini senza perdere informazioni ed è in grado di
memorizzarle in colori reali (quindi non ha il limite, come per la GIF, di 256 colori) ed
ha un canale dedicato per la trasparenza.
Inizialmente non tutti i programmi erano in grado di leggere tali immagini ma oggi
giorno è supportato da tutti i maggiori programmi di grafica e di navigazione. Tant'è
che pur essendo scaduto il brevetto sulla GIF, già dal 2003, non si teme minimamente
che l'utilizzo di tale formato possa diminuire.
JPEG, acronimo di Joint Photographic Experts Group, anche esso è un formato
gratuito, è il più diffuso formato di compressione per la memorizzazione di immagini
ed è anche il più comune formato sul web. Ad esso è associata più di un'estensione,
solitamente .jpg o .jpeg ma ce ne sono anche altre.
Sono definiti due metodi di compressione, uno di tipo “lossless”, quindi senza perdita
di informazione ed un altro di tipo “lossy”, basato sull'uso della trasformata discreta
del coseno, cioè con perdita di informazione, per i file che utilizzano questo metodo,
solitamente, sono utilizzate altre estensioni.
Portable Document Format, il cui acronimo è PDF come la stessa estensione è un
formato di file che può contenere sia immagini che testo. É un formato utilizzabile da
chiunque per la creazioni di applicazioni che effettuano operazioni di lettura o
scrittura. Ha la capacità di memorizzare immagini nella risoluzione preferita. Pur
essendo il formato più diffuso nel suo genere, potrebbe presentare dei problemi in fase
di stampa nel caso in cui siano stati usati caratteri locali non settati correttamente nelle
opzioni di stampa oppure che siano presenti dipendenze da alcuni font esterni allo
stesso. In ogni caso per ovviare a questi inconvenienti sono stati standardizzati alcuni
sotto-formati, come il PDF/A, che incorpora le fonti nel file stesso, ai fini di una
portabilità anche nel tempo (stampa anche tra due decenni oltre la creazione del file.
Gianluca Coda 566/557
Pagina 65 di 131
Grazie al rilascio delle specifiche del formato è possibile creare un file PDF
utilizzando molti linguaggi di programmazione. Altro aspetto del formato è la
protezione crittografica che pur essendo attualmente molto debole, non è escluso che
per il futuro sia rafforzata.
6.5.2 I formati immagini interattivi
Il formato SVG, cioè Scalable Vector Graphics, è in grado di visualizzare immagini
scalabili dimensionalmente, grazie ad oggetti di grafica vettoriale. Questo si traduce in
una conservazione della qualità pur ridimensionando l'immagine. Ciò è possibile in
quanto l'immagine è definita matematicamente e non è solo un insieme statico di pixel.
Inoltre è bene osservare che la grafica vettoriale offre il vantaggio di conservare
maggiori informazioni, rispetto alla sua “antagonista”, la grafica “raster”, in minore
spazio ma che ha di contro che necessita di una potenza di calcolo da parte del
processore per l'elaborazione di immagini complesse. Infine è da evidenziare che tale
operazione non è calcolabile a priori, come succede con la grafica “raster”, quindi ci
potremmo trovare nella condizione di non avere abbastanza risorse per completare il
processo. In ogni caso è un formato indicato per grafici o dati cartografici in generale e
non per per fotografie. Tale formato è stato raccomandato dal W3C, già nel 2001, che
lo ha privilegiato ai suoi concorrenti VML e PGML, proposti rispettivamente dalla
coppia Microsoft – Macromedia e dalla coppia Adobe - Sun Microsystems. Oggi
giorno, il formato dovrebbe essere supportato nativamente dalle ultime versioni dei più
diffusi browser mentre per altri è necessario installare dei plug-in sviluppati da Adobe
o da Corel. Per quanto riguarda alcuni casi, tipo Safari, si attende una prossima
implementazione. In ogni caso sono disponibili visualizzatori e librerie specifiche
come la Batik SVG Toolkit per l'integrazione in codice Java.
Gianluca Coda 566/557
Pagina 66 di 131
6.5.3 Le scelte effettuate
Le pagine implementate
i formati statici: su tali file non è possibile interagire se non con i classici strumenti del
proprio visualizzatore di immagini ma che soffrono di una perdita di dettaglio.
Per quanto riguarda le SVG, vista la mia esperienza, posso dire che non è garantita la
compatibilità al 100%; pur istallando diversi plug-in le funzionalità utilizzabili non
sono le stesse a seconda del browser che si utilizza ed in alcuni casi si presentano crash
improvvisi. Quindi, pur riconoscendo grandi potenzialità, credo che sia un formato
ancora acerbo.
A tale scopo è stata implementata una Applet grazie alla quale è possibile visualizzare
il ToolTip (l'etichetta che compare dove è posizionato il puntatore) ed effettuare
operazioni di aumento di dettaglio, nel caso in cui ci interessasse solo un particolare
intervallo (sia in ascisse che ordinate) rielaborando “al volo” un nuovo grafico.
Ovviamente per utilizzare tale strumento è necessario che il nostro browser supporti le
Applet.
L'Applet in pratica viene caricata una sola volta dal nostro browser ed ad ogni
interrogazione riceve in input un parametro che equivale alla stringa corrispondente al
percorso del file contenente i dati e residente sul server da leggere.
Tramite l'inserimento di nuovo codice Java è possibile generare altri eventi associabili
al click del mouse o combinazioni di tasti.
Gianluca Coda 566/557
Pagina 67 di 131
7 Conclusioni e futuri sviluppi
In questa tesi si è progettato e realizzato un generatore di grafici per monitorare
l'attività dei sistemi di attesa (code) e dei job di una Grid.
I requisiti del generatore sono stati definiti con lo scopo di migliorare le funzionalità e
le modalità di utilizzazione di un esistente visualizzatore. L'analisi ha portato ad
individuare alcune tipologie di grafi più adeguati al tipo di variabili e relazioni da
rappresentare. Un particolare diagramma è stato identificato per rappresentare genesi
di popolazioni di attese (Virtual Organization, Gruppi e Code) in varie modalità di
visualizzazione temporale (ad esempio rispetto ad un giorno, una settimana, un mese
etc).
Il generatore grafico è stato progettato secondo tecniche di Ingegneria del Software
attraverso l'utilizzazione di diagrammi UML. Il sistema è stato realizzato secondo
un'architettura che utilizza software Open Source Java, in particolare JFreeChart il
quale garantisce piena compatibilità con tutte le libreria Java, ciò in prospettiva anche
di eventuali estensioni del sistema. Tra le realizzazioni, infine, è stato implementato un
modulo software che rende possibile la visualizzazione dei grafici su WEB.
In relazione agli sviluppi futuri si prevede di aggiungere alcune funzionalità che diano
la possibilità all'utente di scegliere quali dati mostrare nel grafico (selezionando
specifici elementi e parametri della Grid) così da offrire uno strumento che, in maniera
interattiva, consente di confrontare dati in uno stesso grafico. Per la funzionalità
descritta sarebbe utile offrire all'utente la possibilità di scegliere il tipo di
rappresentazione grafica da altre librerie grafiche.
Tra i possibili sviluppi è di un certo interesse lo sviluppo di alcune funzionalità di
monitoraggio che riguardano l'evidenziazione di stati di funzionamento anomalo della
Grid i quali richiedono un intervento dell'amministratore.
Gianluca Coda 566/557
Pagina 68 di 131
8 Bibliografia
[1] UML Jim Arlow, iLa Neustadt, UML e Unified Process, McGraw-Hill, 2003
[2] J. T. Roff, Fondamenti di UML McGraw-Hill, 2003
[3] Winston M.E., Chaffin R., Herrmann D.
A taxonomy of part-whole relations. Cognitive Science 11;417-444; 1987
[4] Artale A., Franconi E., Guarino N., Pazzi L.
Part-Whole Relations in Object-Centred System: An overview. Data & Knowledge
Engineering (DKE) journal 20 (1996) 347-383 – North-Holland, Elsevier
[5] Gnuplot homepage http://www.gnuplot.info/
[6] JFreeChart: http://www.jfree.org/jfreechart/
[7] R. Pesenti, Teoria delle Code o File d'Attesa,
http://venus.unive.it/pesenti/Old/docwww/Didattica/Logistica/Code.pdf
[8] Ian Foster, Carl Kesselman, Steven Tuecke - The Anathomy of the Grid
[9] Ian Foster, Carl Kesselman, Jeffrey M. Nick, Steven Tuecke - The Physiology of the Grid
[10] Cnaf – http://www.cnaf.infn.it/
[11] Luciano Gaido - L'implementazione ed il deployment di una Grid
http://server11.infn.it/testbed-grid/meetings/elba-ita.pdf
Gianluca Coda 566/557
Pagina 69 di 131
9 Appendici – Installazione e funzionamento del sistema
9.1 Messa in esercizio
Insieme ai sorgenti, l'applicazione viene rilasciata sotto forma di java bytecode in
formato .jar. All'interno del jar vi è una classe “Configuratore.java” che rappresenta un
esempio di utilizzo dell'applicazione realizzata. “Configuratore.java” avvia una serie di
thread di esempio per la generazione di grafici a partire da alcuni file dati. È necessario
modificare il metodo main della classe “Configuratore.java” con dei percorsi reali ai
file dei dati. Per avviare l'applicazione d'esempio è necessario dare il seguente
comando di shell bash: java -jar qjmon_viewer.jar
L'interfaccia utente è rilasciata sotto forma di pagine jsp.
La messa in esercizio dell'interfaccia avviene attraverso il deploy su tomcat. Tale
processo può essere eseguito dall'interfaccia di amministrazione web di quest'ultimo o,
più semplicemente, copiando la cartella “qjmon_viewer_gui” nella cartella “webapps”
di Tomcat.
Nella cartella “bin” di Tomcat va creata una cartella “struttura” all'interno della quale
vanno inseriti i link simbolici alle cartelle contenenti i file dei dati (giornalieri,
settimanali, …).
Gianluca Coda 566/557
Pagina 70 di 131
9.2 Guida d'uso
Il sistema di generazione dei grafici presenta un'interfaccia la quale propone all'utente
alcuni modalità di presentazione/visualizzazione dei dati. L'interfaccia ha una forma
del tipo:
Figura 9.2.1 – Esempio di scherma per la visualizzazione degli storici giornalieri.
Nella parte sinistra dell'interfaccia è presente un menu. Attraverso tale menu è
possibile selezionare per ogni entità della Grid (code, VO, gruppo) un grafico. Nel
menu esistono tre modalità di visualizzazione di alberi genetici di flussi:
•(1) albero genetico;
•(2) albero inverso;
Gianluca Coda 566/557
Pagina 71 di 131
•(3) albero ridotto.
Nelle prime due modalità il livello più alto dell'albero (si veda figura XX) è relativo
agli intervalli temporali di osservazione dei dati (assente nella modalità di
visualizzazione albero ridotto). Altra differenza fra i (1), (2) e quelli di tipo (3)
consiste nel fatto che i primi possiedono una rappresentazione dei dati storicizzati
mentre quelli di tipo (3) visualizzano i dati in forma tabellare.
La funzionalità (1) produce una volta attività un grafico del tipo riportato nella figura
9.2.2.
Il secondo livello degli alberi genetici forniscono una rappresentazione delle Code
presenti sulla Grid. Il terzo livello degli alberi visualizzano le VO relative ad ogni
Coda. Infine le voci di quarto livello indicano i gruppi relativi alla VO selezionata.
Figura 9.2.2
Esempio di menu genetico.
Gianluca Coda 566/557
Figura 9.2.3
Esempio di albero genetico inverso
Pagina 72 di 131
Alla selezione di una delle voci del menu, nella parte centrale della schermata, viene
caricata l'applet contenente il relativo grafico, come mostrato nella seguente figura:
Figura 9.2.4 – Esempio di applet grafica relativa ai dati di un generico gruppo.
nella parte inferiore del layout di visualizzazione sono presenti vari bottoni che
consentono di salvare i grafici in vari formati (PNG, JPEG, PDF, SVG).
Nell'immagine in figura è presenta la schermata relativa alla selezione del formato
PDF la quale viene visualizzata attivando il programma di visualizzazione ADOBE
ACROBAT (si veda figura 9.2.5).
Gianluca Coda 566/557
Pagina 73 di 131
Figura 9.2.5 – Esempio di esportazione di un grafico in formato PDF.
La funzionalità consente anche di effettuare un'operazione di zoom sui grafici,
selezionando una desiderata porzione tramite l'utilizzo del mouse.
Nelle figure 9.2.6 e 9.2.7 è riportata un esempio di attivazione della funzionalità di
zoom attraverso le fasi.
Figura 9.2.6 – Dettaglio della funzionalità zoom.
Gianluca Coda 566/557
Pagina 74 di 131
Figura 9.2.7 – Esempio del grafico della figura 9.2.6 a seguito dello zoom.
Un'altra funzione interattiva che l'applet offre sono le etichette che indicano i valori dei
dati in corrispondenza del puntatore del mouse. Nella figura a seguire vi è un esempio
di un'etichetta che indica il nome, la data ed il valore di un dato.
Figura 9.2.8 – Esempio di tooltip.
Gianluca Coda 566/557
Pagina 75 di 131
La schermata relativa al monitoraggio dei Job presenta un menu basato sull'albero
genetico ridotto
Figura 9.2.9 – Esempio di albero genetico ridotto.
La rappresentazione utilizzata in questo caso è in forma tabellare come è possibile
osservare dall'esempio in figura:
Figura 9.2.10 – Esempio di schermata relativa ai dati di monitoraggio di una VO.
Gianluca Coda 566/557
Pagina 76 di 131
nel caso in cui non sono presenti dati per una voce selezionata viene mostrata una
tabella contenente unicamente l'intestazione.
Figura 9.2.11 – Esempio di schermata relativa ad una tabella vuota.
Gianluca Coda 566/557
Pagina 77 di 131
9.3 Codice sorgente
CONFIGURATORE.JAVA:
package qjmon;
import
import
import
import
import
import
import
import
import
import
qjmon.viewer.ConcatenatoreVO;
qjmon.viewer.GeneratoreGrafici;
qjmon.viewer.ConcatenatoreGruppi;
qjmon.viewer.Grafico;
java.io.File;
java.io.IOException;
java.util.LinkedList;
java.util.logging.Level;
java.util.logging.Logger;
java.util.regex.Pattern;
/**
* Classe main con la responsabilità di inizializzare ed avviare i
thread
* dell'applicazione.
*
* @author Gianluca Coda
*/
public class Configuratore {
//Cartella contenente i dati giornalieri
private static final String folderDatiGiornalieri = new String
("/root/apache-tomcat-6.0.24/webapps/definitivo/giornalieri");
//Cartella contenente i dati settimanali
private static final String folderDatiSettimanali = new String
("/root/apache-tomcat-6.0.24/webapps/definitivo/settimanali/");
//Frequenza di aggiornamento, in secondi, per i dati giornalieri
private static final int refrehGiornalieri = 10;
//Frequenza di aggiornamento, in secondi, per i dati settimanali
private static final int refreshSettimanali = 50;
//Estensioni file nel primo livello
private static final String firstLevelExt = ".VOconc";
//Estensioni file nel secondo livello
private static final String secondLevelExt = ".coda";
//Estensioni file nel terzo livello
private static final String thirdLevelExtFirst = ".vo";
//Estensioni di secondo tipo dei file nel terzo livello
private static final String thirdLevelExtSecond = ".GRconc";
//Estensioni file nel quarto livello
private static final String fourthLevelExt = ".gruppo";
Gianluca Coda 566/557
Pagina 78 di 131
/**
* Avvia i thread per la concatenazione dei file
*
* @param refresh
* frequenza di aggiornamento delle concatenazioni
*
* @param rootFolder
* directory sorgente contenente i file da concatenare
*
* @throws IOException
* in caso di errori durante l'avvio dei concatenatori
*/
private static void avviaConcatenatore(int refresh, String
rootFolder) throws IOException {
//Crea un concatenatore per i gruppi
ConcatenatoreGruppi concatenatoreGruppi = new
ConcatenatoreGruppi(refresh,rootFolder);
//Crea un thread per concatenare i gruppi
Thread threadConcatenatoreGruppi = new
Thread(concatenatoreGruppi);
//Avvia il thread per la concatenazione dei gruppi
threadConcatenatoreGruppi.start();
//Crea un concatenatore per le VO
ConcatenatoreVO concatenatoreVO = new
ConcatenatoreVO(refresh,rootFolder);
//Crea un thread per concatenare le VO
Thread threadConcatenatoreVO = new Thread(concatenatoreVO);
//Avvia il thread per la concatenazione delle VO
threadConcatenatoreVO.start();
}
/**
* Avvia i generatori di grafici.
*
* @param refresh
* frequenza di aggiornamento dei grafici
*
* @param rootFolder
* cartella sorgente contenente i file dei dati da graficare
*/
private static void avviaGeneratoreGrafici(int refresh, String
rootFolder) {
LinkedList<Grafico> listaGrafici = new LinkedList<Grafico>();
File root = new File(rootFolder);
if (root.isFile())
throw new RuntimeException(rootFolder+" isn't a
directory");
Gianluca Coda 566/557
Pagina 79 di 131
for (File firstLevelFile : root.listFiles())
if (firstLevelFile.isFile() &&
firstLevelFile.getName().substring(firstLevelFile.ge
tName().length()-firstLevelExt.length()).equals(firstLevelExt))
listaGrafici.add(new
Grafico(firstLevelFile.getAbsolutePath(),
firstLevelFile.getAbsolutePath()));
else
if (firstLevelFile.isDirectory())
for (File secondLevelFile :
firstLevelFile.listFiles())
if (secondLevelFile.isFile() &&
secondLevelFile.getName().substring(seco
ndLevelFile.getName().length()secondLevelExt.length()).equals(secondLevelExt))
listaGrafici.add(new
Grafico(secondLevelFile.getAbsolutePath(),
secondLevelFile.getAbsolutePath()));
else
if (secondLevelFile.isDirectory())
for (File thirdLevelFile :
secondLevelFile.listFiles())
if (thirdLevelFile.isFile() &&
(
thirdLevelFile.getName().sub
string(thirdLevelFile.getName().length()thirdLevelExtFirst.length()).equals(thirdLevelExtFirst)
||
thirdLevelFile.getName().sub
string(thirdLevelFile.getName().length()thirdLevelExtSecond.length()).equals(thirdLevelExtSecond)
)
)
listaGrafici.add(new
Grafico(thirdLevelFile.getAbsolutePath(),
thirdLevelFile.getAbsolutePath()));
(thirdLevelFile.isDirectory())
else
if
for (File
fourthLevelFile : thirdLevelFile.listFiles())
if
(fourthLevelFile.isFile() &&
fourthLevelFile.
getName().substring(fourthLevelFile.getName().length()fourthLevelExt.length()).equals(fourthLevelExt)
Gianluca Coda 566/557
Pagina 80 di 131
)
listaGrafici.add
(new Grafico(fourthLevelFile.getAbsolutePath(),
fourthLevelFile.getAbsolutePath()));
for(Grafico gr : listaGrafici) {
System.out.println(gr.toString());
}
GeneratoreGrafici generatore = new
GeneratoreGrafici(refresh, listaGrafici);
Thread threadGeneratore = new Thread (generatore);
threadGeneratore.start();
}
/**
* Metodo main
*
* @param args
* parametri ignorati
*
* @throws IOException
* in caso di errori durante i processi di i/o
*/
public static void main (String[]args) throws IOException{
//Avvia i concatenatori per i dati giornalieri
avviaConcatenatore(refrehGiornalieri,
folderDatiGiornalieri);
//Avvia i concatenatori per i dati settimanali
avviaConcatenatore(refreshSettimanali,
folderDatiSettimanali);
try {
Thread.sleep(10000);
} catch (InterruptedException ex) {
Logger.getLogger(Configuratore.class.getName()).log(Leve
l.SEVERE, null, ex);
}
//Avvia i generatori di grafici per i dati giornalieri
avviaGeneratoreGrafici(refrehGiornalieri,
folderDatiGiornalieri);
//Avvia i generatori di grafici per i dati settimanali
avviaGeneratoreGrafici(refreshSettimanali,
folderDatiSettimanali);
}
}
Gianluca Coda 566/557
Pagina 81 di 131
CONCATENATORE.JAVA:
package qjmon.viewer;
import java.io.File;
/**
* Classe astratta per un generico concatenatore di file.
*
* @author Gianluca Coda
*/
public abstract class Concatenatore implements Runnable{
/**
* Ritorna il frequenza di aggiornamento per il concatenatore.
*
* @return
* frequenza di aggiornamento per il concatenatore
*/
public abstract int getRefreshTime();
la
/**
* Ritorna l'oggetto File relativo alla cartella root contenente
* struttura di cartelle e file di dati.
*
* @return
* File relativo alla cartella root contenente la struttura di
cartelle
* e file di dati.
*/
public abstract File getRootFolder();
/**
* Ritorna l'estensione dei file di dati usati dal
concatenatore.
*
* @return
* estensione dei file di dati usati dal concatenatore.
*/
public abstract String getFileExt();
/**
* Imposta l'estensione dei file di dati usati dal
concatenatore.
*
* @param fileExt
* estensione dei file di dati usati dal concatenatore.
*/
Gianluca Coda 566/557
Pagina 82 di 131
public abstract void setFileExt(String fileExt);
/**
* Ritorna l'estensione del file di output ottenuto dal processo
* di concatenazione.
*
* @return
* estensione del file di output ottenuto dal processo
* di concatenazione.
*/
public abstract String getOutputFileExt();
/**
* Imposta l'estensione per il file di dati ottenuto dalla
concatenazione.
*
* @param fileExt
* estensione del file di dati ottenuto dalla concatenazione.
*/
public abstract void setOutputFileExt(String outputFileExt);
}
CONCATENATOREGRUPPI.JAVA:
package qjmon.viewer;
import
import
import
import
import
import
import
import
import
import
import
import
import
import
java.io.BufferedReader;
java.io.File;
java.io.FileInputStream;
java.io.FileNotFoundException;
java.io.FileOutputStream;
java.io.IOException;
java.io.InputStreamReader;
java.io.PrintStream;
java.util.HashMap;
java.util.LinkedList;
java.util.NoSuchElementException;
java.util.StringTokenizer;
java.util.logging.Level;
java.util.logging.Logger;
/**
* Classe che implementa un concatenatore per i gruppi delle vo.
* Il risultato viene salvato in un nuovo file.
*
Gianluca Coda 566/557
Pagina 83 di 131
* @author Gianluca Coda
*/
public class ConcatenatoreGruppi extends Concatenatore {
private int refreshTime;
concatenazione
private File rootFolder;
cartelle e
//Frequenza di aggiornamento
//Root della struttura delle
// file dei dati
private String groupFileExt = ".gruppo";
//Estensione dei file
dei dati
private String concFileExt = ".GRconc"; //Estensione del file
ottenuto dalla
// concatenazione
/**
* Crea un nuovo oggetto atto alla concatenazione dei file dei
gruppi
*
* @param refreshTime
* Frequenza di aggiornamento concatenazione
*
* @param pathNameRootFolder
* Pathname (percorso completo) alla cartella root contenente la
struttura
* di cartelle e file dei dati
*
* @throws IOException
* In caso di errori nell'individuazione della cartella root
*/
public ConcatenatoreGruppi(int refreshTime, String
pathNameRootFolder) throws IOException {
this.refreshTime = refreshTime;
rootFolder = new File(pathNameRootFolder);
if (!rootFolder.isDirectory())
throw new IOException(pathNameRootFolder+" isn't a
directory");
}
@Override
public void run() {
LinkedList<File> fileList = null;
//Lista dei file dei
dati
code)
//Ciclo infinito
while(true) {
//Ciclo sulle sottodirectory della root (directory delle
for (File codeDir : rootFolder.listFiles()) {
Gianluca Coda 566/557
Pagina 84 di 131
//Per ogni directory delle code
if (codeDir.isDirectory())
//Ciclo sulle sottodirectory delle code
(directory delle vo)
for (File voDir : codeDir.listFiles()) {
//Per ogni directory delle vo
if (voDir.isDirectory() ) {
//Aggiunge i file dei gruppi della vo
alla lista file
fileList = visita(voDir);
try {
//Assegnazione nome per il file da
creare ottenuto
// dalla concatenazione dei file dei
gruppi
// della vo in esame
String fileName = voDir.getPath()
+"/"+voDir.getName()+concFileExt;
//Concatena tutti i file della lista
salvandone
// il risultato in un nuovo file
(fileName)
concatena(fileList, fileName);
} catch (FileNotFoundException ex) {
//Log di eventuali eccezioni per
file non trovato
Logger.getLogger(ConcatenatoreGruppi
.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
//Log di eventuali eccezioni di i/o
su file
Logger.getLogger(ConcatenatoreGruppi
.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
try {
//Attende refreshTime secondi prima di effettuare
nuovamente
// la concatenazione
Thread.sleep(refreshTime * 1000);
} catch (InterruptedException ex) {
//In caso di interruzione del thread mostra su
stdout lo stack
// dell'eccezione
ex.printStackTrace();
}
}
Gianluca Coda 566/557
Pagina 85 di 131
}
/**
* Metodo privato che, a partire dalla cartella "voFolder",
ritorna
* una lista di file contenenti i dati dei gruppi.
*
* @param voFolder
* file che punta alla directory di una vo
*
* @return
* lista di file contenenti i dati dei gruppi
*/
private LinkedList<File> visita(File voFolder) {
LinkedList<File> fileList = new LinkedList<File>(); //Lista
da ritornare
//Ciclo su file e sottodirectory della cartella della vo
for (File groupDir : voFolder.listFiles())
//Per ogni sottodirectory della vo (cartella di un
gruppo)
un gruppo
if (groupDir.isDirectory())
//Per ogni file e sottodirectory della cartella di
for (File groupFile : groupDir.listFiles())
//Per ogni file contenente dati di un gruppo
if (groupFile.isFile() &&
groupFile.getPath().endsWith(groupFileExt))
fileList.add(groupFile);
//Aggiunge il
file alla lista
return fileList;
//Ritorna la lista dei file dei gruppi
}
// i nomi delle etichette devono essere ricavati dai nomi delle
cartelle in cui si
// trovano i file. Quindi è la concatenazione del nome della
cartella più il nome della
// etichetta.
/**
* Esegue la concatenazione dei file della lista "fileList"
memorizzandone
* il risultato in un nuovo file con pathname pari ad
"outputFileName".
*
* @param fileList
* lista di file da concatenare
*
Gianluca Coda 566/557
Pagina 86 di 131
* @param outputFileName
* pathname del nuovo file che conterra' i dati della
concatenazione
*
* @return
* oggetto File che punta al file ottenuto dalla concatenazione
*
* @throws FileNotFoundException
* nel caso in cui un file non viene trovato
*
* @throws IOException
* in caso di errori nel processo di i/o su file
*/
private File concatena(LinkedList<File> fileList, String
outputFileName) throws FileNotFoundException, IOException {
LinkedList<HashMap<Integer, LinkedList<String>>>
dataFileList = new LinkedList<HashMap<Integer,
LinkedList<String>>>();
int fileNumber = fileList.size();
File outputFile = new File(outputFileName);
FileInputStream streamin = null;
InputStreamReader readerin = null;
BufferedReader readerbuff = null;
StringTokenizer stringatok = null;
String valoreCampo = null;
String stringa = null;
HashMap<Integer, LinkedList<String>> dataFileMap = null;
int rowCount = 0;
int colCount = 0;
for (File fileI : fileList) {
dataFileMap = new HashMap<Integer,
LinkedList<String>>();
streamin = new FileInputStream(fileI);
readerin = new InputStreamReader(streamin);
readerbuff = new BufferedReader(readerin);
rowCount = 0;
for (stringa = readerbuff.readLine(); stringa != null;
stringa = readerbuff.readLine()) {
colCount = 0;
stringatok = new StringTokenizer(stringa);
LinkedList<String> row = new LinkedList<String>();
try {
for (colCount = 0; ; ++colCount) {
valoreCampo = stringatok.nextToken();
Gianluca Coda 566/557
Pagina 87 di 131
row.add(valoreCampo);
}
}catch (NoSuchElementException ex) {}
dataFileMap.put(rowCount, row);
++rowCount;
}
dataFileList.add(dataFileMap);
}
FileOutputStream streamout = new
FileOutputStream(outputFile);
PrintStream output = new PrintStream(streamout);
for (int i = 0; i < rowCount; ++i) {
int fileCount = 0;
for (int j = 0; j < colCount; ++j) {
for (HashMap<Integer, LinkedList<String>> fileMap :
dataFileList) {
LinkedList<String> valueList = fileMap.get(i);
String valore = valueList.get(j); //inserire
controllo IF per primo rigo
if (i == 0) {//inserito per prova
String prefix =
fileList.get(fileCount).getName();
prefix = prefix.substring(0,
prefix.length()-groupFileExt.length());
valore = prefix+"_"+valore;
//System.out.print(prefix+"_"+valore+"\t");
//inserito per prova
//sto sul fileCount per ottenere il nome del
file fileList.get(fileCount).getPath
}
if (j == 0 && fileCount == 0)
output.print(valore+"\t");
if (j != 0)
output.print(valore+"\t");
++fileCount;
}
fileCount=0;
}
output.println();
}
return outputFile;
}
@Override
Gianluca Coda 566/557
Pagina 88 di 131
public int getRefreshTime() {
return refreshTime;
}
@Override
public File getRootFolder() {
return rootFolder;
}
@Override
public String getFileExt() {
return groupFileExt;
}
@Override
public void setFileExt(String fileExt) {
this.groupFileExt = fileExt;
}
@Override
public String getOutputFileExt() {
return concFileExt;
}
@Override
public void setOutputFileExt(String outputFileExt) {
this.concFileExt = outputFileExt;
}
}
CONCATENATOREVO.JAVA:
package qjmon.viewer;
import
import
import
import
import
import
import
import
import
import
java.io.BufferedReader;
java.io.File;
java.io.FileInputStream;
java.io.FileNotFoundException;
java.io.FileOutputStream;
java.io.IOException;
java.io.InputStreamReader;
java.io.PrintStream;
java.util.HashMap;
java.util.LinkedList;
Gianluca Coda 566/557
Pagina 89 di 131
import
import
import
import
java.util.NoSuchElementException;
java.util.StringTokenizer;
java.util.logging.Level;
java.util.logging.Logger;
/**
* Classe che implementa un concatenatore per le vo di una coda.
* Il risultato viene salvato in un nuovo file.
*
* @author Gianluca Coda
*/
public class ConcatenatoreVO extends Concatenatore {
private int refreshTime;
concatenazione
private File rootFolder;
cartelle e
//Frequenza di aggiornamento
//Root della struttura delle
// file dei dati
private String voFileExt = ".vo";
//Estensione dei file dei
dati
private String concFileExt = ".VOconc"; //Estensione del file
ottenuto dalla
// concatenazione
/**
* Crea un nuovo oggetto atto alla concatenazione dei file dei
gruppi
*
* @param refreshTime
* Frequenza di aggiornamento concatenazione
*
* @param pathNameRootFolder
* Pathname (percorso completo) alla cartella root contenente la
struttura
* di cartelle e file dei dati
*
* @throws IOException
* In caso di errori nell'individuazione della cartella root
*/
public ConcatenatoreVO(int refreshTime, String
pathNameRootFolder) throws IOException {
this.refreshTime = refreshTime;
rootFolder = new File(pathNameRootFolder);
if (!rootFolder.isDirectory())
throw new IOException(pathNameRootFolder+" isn't a
directory");
}
Gianluca Coda 566/557
Pagina 90 di 131
@Override
public void run() {
LinkedList<File> fileList = null;
concatenare
String concFileName = null;
salvataggio del
//Lista dei file da
//Pathname per il
// file ottenuto dalla
concatenazione
concFileName = rootFolder+"/";
//Ciclo infinito
while(true) {
fileList = visita();
try {
LinkedList<File> voFileList = null;
File fileTmp = null;
File fileHead = null;
//Ciclo sulla lista dei file da concatenare
for (; !fileList.isEmpty();) {
voFileList = new LinkedList<File>();
fileHead = fileList.poll();
voFileList.add(fileHead);
for (int i = 0; i < fileList.size(); ++i) {
fileTmp = fileList.get(i);
if
(fileTmp.getName().equals(fileHead.getName())) {
fileList.remove(i);
voFileList.add(fileTmp);
--i;
}
}
//Concatena i file
concatena(voFileList,
concFileName+fileHead.getName()+concFileExt);
}
} catch (FileNotFoundException ex) {
//Logga eventuali errori dovuti all'accesso a file
Logger.getLogger(ConcatenatoreVO.class.getName()).lo
g(Level.SEVERE, null, ex);
} catch (IOException ex) {
//Logga eventuali errori durante i processi di i/o
su file
Logger.getLogger(ConcatenatoreVO.class.getName()).lo
g(Level.SEVERE, null, ex);
}
try {
//Attende refreshTime secondi prima di effettuare
Gianluca Coda 566/557
Pagina 91 di 131
nuovamente
// la concatenazione
Thread.sleep(refreshTime * 1000);
} catch (InterruptedException ex) {
//In caso di interruzione del thread mostra su
stdout lo stack
// dell'eccezione
ex.printStackTrace();
}
}
}
/**
* Metodo privato che ritorna una lista di file contenenti i
dati delle VO.
*
* @return
* lista di file contenenti i dati delle VO
*/
private LinkedList<File> visita() {
LinkedList<File> fileList = new LinkedList<File>();
for (File codeDir : rootFolder.listFiles())
if (codeDir.isDirectory())
for (File voDir : codeDir.listFiles())
if (voDir.isDirectory())
for (File voFile : voDir.listFiles())
if (voFile.isFile() &&
voFile.getPath().endsWith(voFileExt))
fileList.add(voFile);
}
return fileList;
/**
* Esegue la concatenazione dei file della lista "fileList"
memorizzandone
* il risultato in un nuovo file con pathname pari ad
"outputFileName".
*
* @param fileList
* lista di file da concatenare
*
* @param outputFileName
* pathname del nuovo file che conterra' i dati della
concatenazione
*
* @return
* oggetto File che punta al file ottenuto dalla concatenazione
*
Gianluca Coda 566/557
Pagina 92 di 131
* @throws FileNotFoundException
* nel caso in cui un file non viene trovato
*
* @throws IOException
* in caso di errori nel processo di i/o su file
*/
private File concatena(LinkedList<File> fileList, String
outputFileName) throws FileNotFoundException, IOException {
LinkedList<HashMap<Integer, LinkedList<String>>>
dataFileList = new LinkedList<HashMap<Integer,
LinkedList<String>>>();
int fileNumber = fileList.size();
File outputFile = new File(outputFileName);
FileInputStream streamin = null;
InputStreamReader readerin = null;
BufferedReader readerbuff = null;
StringTokenizer stringatok = null;
String valoreCampo = null;
String stringa = null;
HashMap<Integer, LinkedList<String>> dataFileMap = null;
int rowCount = 0;
int colCount = 0;
for (File fileI : fileList) {
dataFileMap = new HashMap<Integer,
LinkedList<String>>();
streamin = new FileInputStream(fileI);
readerin = new InputStreamReader(streamin);
readerbuff = new BufferedReader(readerin);
rowCount = 0;
for (stringa = readerbuff.readLine(); stringa != null;
stringa = readerbuff.readLine()) {
colCount = 0;
stringatok = new StringTokenizer(stringa);
LinkedList<String> row = new LinkedList<String>();
try {
for (colCount = 0; ; ++colCount) {
valoreCampo = stringatok.nextToken();
row.add(valoreCampo);
}
}catch (NoSuchElementException ex) {}
dataFileMap.put(rowCount, row);
++rowCount;
}
Gianluca Coda 566/557
Pagina 93 di 131
dataFileList.add(dataFileMap);
}
FileOutputStream streamout = new
FileOutputStream(outputFile);
PrintStream output = new PrintStream(streamout);
for (int i = 0; i < rowCount; ++i) {
int fileCount = 0;
for (int j = 0; j < colCount; ++j) {
for (HashMap<Integer, LinkedList<String>> fileMap :
dataFileList) {
LinkedList<String> valueList = fileMap.get(i);
String valore = valueList.get(j); //inserire
controllo IF per primo rigo
if (i == 0) {//inserito per prova
String prefix =
fileList.get(fileCount).getPath();
// concFile fileName
int x = rootFolder.getPath().length() + 1;
//System.out.println("x: "+x);
//System.out.println("nome file:
"+fileList.get(fileCount).getName());
int y = prefix.length() 2*(fileList.get(fileCount).getName().length()) + voFileExt.length()
- 2;
prefix = prefix.substring(x, y);
valore = prefix+"_"+valore;
//System.out.print(prefix+"_"+valore+"\t");
//inserito per prova
//sto sul fileCount per ottenere il nome del
file fileList.get(fileCount).getPath
}
if (j == 0 && fileCount == 0)
output.print(valore+"\t");
if (j != 0)
output.print(valore+"\t");
++fileCount;
}
fileCount=0;
}
}
output.println();
streamin.close();
readerin.close();
readerbuff.close();
streamout.close();
output.close();
Gianluca Coda 566/557
Pagina 94 di 131
return outputFile;
}
@Override
public int getRefreshTime() {
return refreshTime;
}
@Override
public File getRootFolder() {
return rootFolder;
}
@Override
public String getFileExt() {
return voFileExt;
}
@Override
public void setFileExt(String fileExt) {
this.voFileExt = fileExt;
}
@Override
public String getOutputFileExt() {
return concFileExt;
}
@Override
public void setOutputFileExt(String outputFileExt) {
this.concFileExt = outputFileExt;
}
}
GENERATOREGRAFICI.JAVA:
package qjmon.viewer;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.LinkedList;
/**
* Classe per la generazione di grafici a partire da un file dei
Gianluca Coda 566/557
Pagina 95 di 131
dati.
*
* @author Gianluca Coda
*/
public class GeneratoreGrafici implements Runnable {
private int refreshTime; //Frequenza, in secondi, di generazione
dei grafici
private LinkedList<Grafico> listaGrafici;
//Lista di grafici
da generare
/**
* Crea un nuovo oggetto atto alla generazione, ad intervalli di
tempo
* regolari, di grafici.
*
* @param refreshTime
* frequenza, in secondi, per l'aggiornamento dei grafici.
*
* @param listaGrafici
* lista di grafici da generare ed aggiornare.
*/
public GeneratoreGrafici (int refreshTime, LinkedList<Grafico>
listaGrafici){
this.refreshTime = refreshTime;
this.listaGrafici = listaGrafici;
}
@Override
public void run() {
//Ciclo infinito
while (true){
//Ciclo sui grafici da generare
for (Grafico grafico: listaGrafici){
try {
//Genera il grafico
grafico.generaGrafico();
} catch (FileNotFoundException ex) {
//In caso di errore nell'accesso al file dei
dati
ex.printStackTrace();
} catch (IOException ex) {
//In caso di errori durante i processi di i/o
ex.printStackTrace();
}
}
try {
//Attende refreshTime secondi prima di effettuare
nuovamente
Gianluca Coda 566/557
Pagina 96 di 131
}
}
// la generazione dei grafici
Thread.sleep(refreshTime * 1000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
GRAFICO:
package qjmon.viewer;
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Rectangle;
import com.lowagie.text.pdf.FontMapper;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfTemplate;
import com.lowagie.text.pdf.PdfWriter;
import java.awt.Graphics2D;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Locale;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.labels.StandardXYToolTipGenerator;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.StackedXYAreaRenderer2;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.data.xy.DefaultTableXYDataset;
import org.jfree.data.xy.TableXYDataset;
import org.jfree.data.xy.XYSeries;
import
org.jfree.experimental.chart.renderer.xy.XYSmoothLineAndShapeRendere
r;
Gianluca Coda 566/557
Pagina 97 di 131
import
import
import
import
import
import
import
import
import
import
java.awt.geom.Rectangle2D;
java.io.File;
java.io.FileOutputStream;
java.io.IOException;
java.io.OutputStreamWriter;
java.io.Writer;
org.apache.batik.dom.GenericDOMImplementation;
org.apache.batik.svggen.SVGGraphics2D;
org.jfree.chart.JFreeChart;
org.w3c.dom.DOMImplementation;
/**
* Classe che rappresenta un generico grafico
*
* @author Gianluca Coda
*/
public class Grafico {
private static final char tagLine = '*';//Tag per i dati da
plottare come linee
private static final char tagNoPlot = '!';//Tag per i dati che
devono essere ignorati
private String pathNameData;
//Percorso al file dei dati
private String pathNameGraph;
//Nome del file, senza
estensione,
// per il salvataggio del
grafico
private final static int costantTime = 1000;
/**
* Crea un nuovo grafico riferito ai dati del file
"pathNameData".
*
* @param pathNameData
* pathname al file contenente i dati da plottare.
*
* @param pathNameGraph
* nome del file, senza estensione, con cui salvare il grafico
*/
public Grafico (String pathNameData, String pathNameGraph){
this.pathNameData = pathNameData;
this.pathNameGraph = pathNameGraph;
}
/**
* Crea un oggetto JFreeChart a partire dal dataset passato come
* parametro. Il grafico è del tipo "aree impilate" (Stacked)
*
Gianluca Coda 566/557
Pagina 98 di 131
* @param dataset
* dataset da plottare.
*
* @return
* oggetto JFreeChart rappresentante il grafico ottenuto dal
dataset
* passato come parametro.
*/
private JFreeChart createChart(TableXYDataset dataset) {
//Generazione etichette
StandardXYToolTipGenerator labelGenerator = new
StandardXYToolTipGenerator(
StandardXYToolTipGenerator.DEFAULT_TOOL_TIP_FORMAT,
new SimpleDateFormat("dd-MMM-yyyy", Locale.ITALY),
NumberFormat.getInstance()
);
//Imposta il nome dell'asse delle x
DateAxis xAxis = new DateAxis("Time");
//Imposta i margini superiori ed inferiori del grafico per
l'asse x
xAxis.setLowerMargin(0.0);
xAxis.setUpperMargin(0.0);
//Imposta il nome dell'asse delle y
NumberAxis yAxis = new NumberAxis("Job");
//Imposta l'unità di misura delle y (interi)
yAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits
());
//Imposta il grafico come aree impilate
StackedXYAreaRenderer2 renderer = new
StackedXYAreaRenderer2(labelGenerator, null);
XYPlot plot = new XYPlot(dataset, xAxis, yAxis, renderer);
//Crea il grafico
JFreeChart chart = new JFreeChart(null,
JFreeChart.DEFAULT_TITLE_FONT, plot, true);
try {
//Salvataggio grafico in formato png (risoluzione
500x300)
ChartUtilities.saveChartAsPNG(new
File(pathNameGraph+".png"), chart, 500,300);
//Salvataggio grafico in formato jpeg (risoluzione
500x300)
ChartUtilities.saveChartAsJPEG(new
File(pathNameGraph+".jpg"), chart, 500,300);
//Salvataggio grafico in formato pdf (risoluzione
Gianluca Coda 566/557
Pagina 99 di 131
500x300)
OutputStream out = new BufferedOutputStream(new
FileOutputStream(pathNameGraph+".pdf"));
writeChartAsPDF(out, chart, 500, 300, null);
out.close();
//Salvataggio grafico in formato svg (risoluzione
500x300)
DOMImplementation domImpl =
GenericDOMImplementation.getDOMImplementation();
// Creazione di un'instanza di org.w3c.dom.Document
org.w3c.dom.Document document =
domImpl.createDocument(null, "svg", null);
// Creazione di un'istanza di Generatore SVG
SVGGraphics2D svgGenerator = new
SVGGraphics2D(document);
// imposta la precisione al fine di evitare eccezioni
dovute a puntatori null
// nella Batik 1.5
svgGenerator.getGeneratorContext().setPrecision(6);
// Importa il rendering del grafico per la SVG
Graphics2D
chart.draw(svgGenerator, new Rectangle2D.Double(0, 0,
500, 300), null);
// Salvataggio SVG
boolean useCSS = true;
Writer out_svg = new OutputStreamWriter(
new FileOutputStream(new
File(pathNameGraph+".svg")), "UTF-8");
svgGenerator.stream(out_svg, useCSS);
} catch (Exception e) {
//In caso di errori nel salvataggio del grafico
System.out.println("Problema nella esportazione del
grafico");
}
}
//Ritorna il grafico creato
return chart;
// crea un grafico con primo dataset a linea ed il secondo
impilato
Gianluca Coda 566/557
Pagina 100 di 131
/**
* Crea un oggetto JFreeChart a partire dai dataset passati come
* parametri. Il primo dataset viene graficato "a linee", mentre
il secondo
* come "aree impilate".
*
* @param lineDataset
* dataset da rappresentare come linee.
*
* @param stackedDataset
* dataset da rappresentare come aree impilate.
*
* @return
* oggetto JFreeChart rappresentante il grafico ottenuto dai
dataset
* passati come parametri.
*/
private JFreeChart createChart(TableXYDataset lineDataset,
TableXYDataset stackedDataset) {
//Generazione etichette
StandardXYToolTipGenerator labelGenerator = new
StandardXYToolTipGenerator(
StandardXYToolTipGenerator.DEFAULT_TOOL_TIP_FORMAT,
new SimpleDateFormat("dd-MMM-yyyy", Locale.ITALY),
NumberFormat.getInstance()
);
x
//Imposta il nome dell'asse x
DateAxis xAxis = new DateAxis("Time");
//Imposta margini superiori ed inferiori del grafico per l'asse
xAxis.setLowerMargin(0.0);
xAxis.setUpperMargin(0.0);
//Imposta il nome dell'asse y
NumberAxis yAxis = new NumberAxis("Job");
//Imposta l'unità di misura per l'asse y (interi)
yAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits
());
//Imposta il renderer per il dataset a linee
XYSmoothLineAndShapeRenderer renderer = new
XYSmoothLineAndShapeRenderer();
XYPlot plot = new XYPlot(lineDataset, xAxis, yAxis,
renderer);
plot.setDataset(1, stackedDataset);
Gianluca Coda 566/557
Pagina 101 di 131
//Imposta il renderer per il dataset ad aree impilate
XYItemRenderer renderer1 = new
StackedXYAreaRenderer2(labelGenerator, null);
plot.setRenderer(1, renderer1);
//Crea il grafico
JFreeChart chart = new JFreeChart(null,
JFreeChart.DEFAULT_TITLE_FONT, plot, true);
500x300)
try {
//Salvataggio grafico in formato png (risoluzione
ChartUtilities.saveChartAsPNG(new
File(pathNameGraph+".png"), chart, 500,300);
//Salvataggio grafico in formato jpeg (risoluzione
500x300)
ChartUtilities.saveChartAsJPEG(new
File(pathNameGraph+".jpg"), chart, 500,300);
//Salvataggio grafico in formato pdf (risoluzione
500x300)
OutputStream out = new BufferedOutputStream(new
FileOutputStream(pathNameGraph+".pdf"));
writeChartAsPDF(out, chart, 500, 300, null);
out.close();
//Salvataggio grafico in formato svg (risoluzione
500x300)
DOMImplementation domImpl =
GenericDOMImplementation.getDOMImplementation();
// Creazione di un'instanza di org.w3c.dom.Document
org.w3c.dom.Document document =
domImpl.createDocument(null, "svg", null);
// Creazione di un'istanza di Generatore SVG
SVGGraphics2D svgGenerator = new
SVGGraphics2D(document);
// imposta la precisione al fine di evitare eccezioni
dovute a puntatori null
// nella Batik 1.5
svgGenerator.getGeneratorContext().setPrecision(6);
// Importa il rendering del grafico per la SVG
Graphics2D
Gianluca Coda 566/557
Pagina 102 di 131
chart.draw(svgGenerator, new Rectangle2D.Double(0, 0,
500, 300), null);
// Salvataggio SVG
boolean useCSS = true;
Writer out_svg = new OutputStreamWriter(
new FileOutputStream(new
File(pathNameGraph+".svg")), "UTF-8");
svgGenerator.stream(out_svg, useCSS);
} catch (Exception e) {
//In caso di errori nel salvataggio del grafico
System.out.println("Problema nella esportazione del
grafico");
}
}
return chart; //Ritorna il grafico creato
/**
* Genera il grafico.
*
* @throws FileNotFoundException
* in caso di errori nell'accesso al file dei dati.
*
* @throws IOException
* in caso di errori durante i processi di i/o
*/
public void generaGrafico() throws FileNotFoundException,
IOException{
DefaultTableXYDataset stackedDataset = new
DefaultTableXYDataset();
DefaultTableXYDataset lineDataset = new
DefaultTableXYDataset();
HashMap<Integer, XYSeries> mappaCurve = new HashMap<Integer,
XYSeries>();
HashMap<Integer, XYSeries> mappaAree = new HashMap<Integer,
XYSeries>();
File dataFile = new File(pathNameData);
FileInputStream streamin = new FileInputStream(dataFile);
InputStreamReader readerin = new
InputStreamReader(streamin);
BufferedReader readerbuff = new BufferedReader(readerin);
String stringa = readerbuff.readLine();
//lettura intestazione file
StringTokenizer stringatok = null;
String valoreCampo = null; //lettura data
Gianluca Coda 566/557
Pagina 103 di 131
int numeroCurve = 0;
if (stringa!=null)
try{
stringatok = new StringTokenizer(stringa);
valoreCampo = stringatok.nextToken(); //lettura data
for (numeroCurve = 0; ; ++numeroCurve ){
valoreCampo = stringatok.nextToken();
if (!(valoreCampo.substring(0,
1)).equals(""+tagNoPlot)) {
if ((valoreCampo.substring(0,
1)).equals(""+tagLine)) {
valoreCampo =
valoreCampo.replaceFirst("["+tagLine+"]", "");
mappaCurve.put(numeroCurve, new
XYSeries(valoreCampo,true,false));
}
else {
mappaAree.put(numeroCurve, new
XYSeries(valoreCampo,true,false));
}
}
}
}
catch(NoSuchElementException ex){
}
//ciclo sulle righe
for (stringa = readerbuff.readLine();stringa != null;){
stringatok = new StringTokenizer(stringa);
try {
Long time =
Long.parseLong(stringatok.nextToken())*costantTime;
//ciclo sulle colonne
for (int i=0; i<numeroCurve ; ++i){
Integer value =
Integer.parseInt(stringatok.nextToken());
XYSeries serie = mappaAree.get(i);
if (serie == null)
serie = mappaCurve.get(i);
if (serie != null)
Gianluca Coda 566/557
Pagina 104 di 131
serie.add(time, value);
}
}catch(NoSuchElementException ex){
ex.printStackTrace();
streamin.close();
readerin.close();
readerbuff.close();
}
stringa = readerbuff.readLine();
}
for (Integer x : mappaAree.keySet()) {
XYSeries serie = mappaAree.get(x);
if (serie != null)
stackedDataset.addSeries(serie);
}
for (Integer x : mappaCurve.keySet()) {
XYSeries serie = mappaCurve.get(x);
if (serie != null)
lineDataset.addSeries(serie);
}
JFreeChart chart = createChart(lineDataset, stackedDataset);
}
public String toString(){
return("Datafile: " + pathNameData + "\t pathNameGraph: " +
pathNameGraph);
}
*
*
*
*
*
*
/**
Salva il grafico nel formato PDF
@param out
stream sul quale scrivere il pdf
@param chart
Gianluca Coda 566/557
Pagina 105 di 131
* grafico da salvare in pdf
*
* @param width
* largezza del pdf
*
* @param height
* altezza del pdf
*
* @param mapper
* mapper per i font da usare nel pdf
*
* @throws IOException
* in caso di errori durante il processo di salvataggio
*/
public static void writeChartAsPDF(OutputStream out,
JFreeChart chart,
int width,
int height,
FontMapper mapper) throws
IOException {
Rectangle pagesize = new Rectangle(width, height);
Document document = new Document(pagesize, 50, 50, 50, 50);
try {
PdfWriter writer = PdfWriter.getInstance(document, out);
document.addAuthor("JFreeChart");
document.addSubject("Demonstration");
document.open();
PdfContentByte cb = writer.getDirectContent();
PdfTemplate tp = cb.createTemplate(width, height);
Graphics2D g2 = tp.createGraphics(width, height, mapper);
Rectangle2D r2D = new Rectangle2D.Double(0, 0, width,
height);
chart.draw(g2, r2D);
g2.dispose();
cb.addTemplate(tp, 0, 0);
}
catch (DocumentException de) {
System.err.println(de.getMessage());
}
document.close();
}
}
Gianluca Coda 566/557
Pagina 106 di 131
APPLETGRAFICA.JAVA
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/**
*
* @author Pensieroso
*/
/* -----------* AppletGrafica.java
* -----------* (C) Copyright 2002-2005, by Object Refinery Limited.
*/
package applet;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Locale;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
import javax.swing.JApplet;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.labels.StandardXYToolTipGenerator;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.StackedXYAreaRenderer2;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.data.xy.DefaultTableXYDataset;
import org.jfree.data.xy.TableXYDataset;
import org.jfree.data.xy.XYSeries;
import
org.jfree.experimental.chart.renderer.xy.XYSmoothLineAndShapeRendere
r;
/**
* A simple applet demo.
*/
public class AppletGrafica extends JApplet {
Gianluca Coda 566/557
Pagina 107 di 131
/** Time series for total memory used. */
//private TimeSeries total;
/** Time series for free memory. */
//private TimeSeries free;
private
private
private
private
String pathNameData = null;
static final char tagLine = '*';
static final char tagNoPlot = '!';
final static int costantTime = 1000;
private
DefaultTableXYDataset
stackedDataset
DefaultTableXYDataset();
private
DefaultTableXYDataset
lineDataset
DefaultTableXYDataset();
=
new
=
new
public void init() {
pathNameData= this.getParameter("stringa");
//this.total = new TimeSeries("Total", Millisecond.class);
//this.total.setMaximumItemAge(30000);
//this.free = new TimeSeries("Free", Millisecond.class);
//this.free.setMaximumItemAge(30000);
//TimeSeriesCollection dataset = new TimeSeriesCollection();
//dataset.addSeries(total);
//dataset.addSeries(free);
//String text=null;
/*try {
URL url = new URL(getDocumentBase(),filePathName);
//DataInputStream
stream
DataInputStream(url.openStream());
BufferedReader buff
InputStreamReader(url.openStream()));
text = buff.readLine();
=
new
=
new
BufferedReader(new
}catch (IOException e){
e.printStackTrace();
}
DateAxis domain = new DateAxis(text);
NumberAxis range = new NumberAxis("Memory");
false);
XYItemRenderer renderer = new XYLineAndShapeRenderer(true,
Gianluca Coda 566/557
Pagina 108 di 131
XYPlot plot = new XYPlot(dataset, domain, range, renderer);
plot.setBackgroundPaint(Color.lightGray);
plot.setDomainGridlinePaint(Color.white);
plot.setRangeGridlinePaint(Color.white);
renderer.setSeriesPaint(0, Color.red);
renderer.setSeriesPaint(1, Color.green);
renderer.setSeriesStroke(0, new BasicStroke(1.5f));
renderer.setSeriesStroke(1, new BasicStroke(1.5f));
domain.setAutoRange(true);
domain.setLowerMargin(0.0);
domain.setUpperMargin(0.0);
domain.setTickLabelsVisible(true);
());
true
);
range.setStandardTickUnits(NumberAxis.createIntegerTickUnits
JFreeChart chart = new JFreeChart(
"Memory Usage", JFreeChart.DEFAULT_TITLE_FONT, plot,
chart.setBackgroundPaint(Color.white);
*/
//stackedDataset = new DefaultTableXYDataset();
//lineDataset = new DefaultTableXYDataset();
HashMap<Integer, XYSeries> mappaCurve = new HashMap<Integer,
XYSeries>();
HashMap<Integer, XYSeries> mappaAree = new HashMap<Integer,
XYSeries>();
try {
URL url = new URL(getDocumentBase(),pathNameData);
BufferedReader readerbuff = new BufferedReader(new
InputStreamReader(url.openStream()));
String stringa = readerbuff.readLine();
//lettura intestazione file
StringTokenizer stringatok = null;
String valoreCampo = null; //lettura data
int numeroCurve = 0;
if (stringa!=null)
try{
stringatok = new StringTokenizer(stringa);
valoreCampo = stringatok.nextToken(); //lettura data
for (numeroCurve = 0; ; ++numeroCurve ){
Gianluca Coda 566/557
Pagina 109 di 131
valoreCampo = stringatok.nextToken();
1)).equals(""+tagNoPlot)) {
if
(!(valoreCampo.substring(0,
if ((valoreCampo.substring(0,
1)).equals(""+tagLine)) {
valoreCampo =
valoreCampo.replaceFirst("["+tagLine+"]", "");
mappaCurve.put(numeroCurve, new
XYSeries(valoreCampo,true,false));
}
else {
mappaAree.put(numeroCurve, new
XYSeries(valoreCampo,true,false));
}
}
}
}
catch(NoSuchElementException ex){
//ex.printStackTrace();
//streamin.close();
//readerin.close();
//readerbuff.close();
}
//ciclo sulle righe
for (stringa = readerbuff.readLine();stringa != null;){
stringatok = new StringTokenizer(stringa);
try {
Long.parseLong(stringatok.nextToken())*costantTime;
Long
time
=
value
=
//ciclo sulle colonne
for (int i=0; i<numeroCurve ; ++i){
Integer
Integer.parseInt(stringatok.nextToken());
XYSeries serie = mappaAree.get(i);
if (serie == null)
serie = mappaCurve.get(i);
if (serie != null)
serie.add(time, value);
//XYSeries serie = seriesList.get(i);
Gianluca Coda 566/557
Pagina 110 di 131
//serie.add(time,value);
}
}catch(NoSuchElementException ex){
ex.printStackTrace();
}
stringa = readerbuff.readLine();
}
//for (XYSeries serie : seriesList)
//
dataset.addSeries(serie);
for (Integer x : mappaAree.keySet()) {
XYSeries serie = mappaAree.get(x);
if (serie != null)
stackedDataset.addSeries(serie);
}
for (Integer x : mappaCurve.keySet()) {
XYSeries serie = mappaCurve.get(x);
if (serie != null)
lineDataset.addSeries(serie);
}
//JFreeChart chart = new JFreeChart("Memory Usage",
JFreeChart.DEFAULT_TITLE_FONT, plot, true);
JFreeChart chart = createChart(lineDataset,
stackedDataset);
ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setPopupMenu(null);
getContentPane().add(chartPanel);
//new AppletGrafica.DataGenerator().start();
}catch(Exception ex) {
ex.printStackTrace();
}
}
Gianluca Coda 566/557
Pagina 111 di 131
private JFreeChart createChart(TableXYDataset
TableXYDataset stackedDataset) {
lineDataset,
StandardXYToolTipGenerator labelGenerator =
StandardXYToolTipGenerator(
StandardXYToolTipGenerator.DEFAULT_TOOL_TIP_FORMAT,
new SimpleDateFormat("dd-MMM-yyyy", Locale.ITALY),
NumberFormat.getInstance()
);
DateAxis xAxis = new DateAxis("Domain (X)");
xAxis.setLowerMargin(0.0);
xAxis.setUpperMargin(0.0);
new
NumberAxis yAxis = new NumberAxis("Range (Y)");
//yAxis.setAutoRangeIncludesZero(true);
yAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits
());
XYSmoothLineAndShapeRenderer
XYSmoothLineAndShapeRenderer();
XYPlot
plot
=
new
renderer
XYPlot(lineDataset,
=
xAxis,
new
yAxis,
renderer);
//XYItemRenderer renderer0 = plot.getRenderer();
plot.setDataset(1, stackedDataset);
XYItemRenderer
StackedXYAreaRenderer2(labelGenerator, null);
renderer1
=
new
plot.setRenderer(1, renderer1);
JFreeChart
chart
=
JFreeChart.DEFAULT_TITLE_FONT, plot, true);
new
JFreeChart(null,
return chart;
}
/**
* Creates AppletGrafica new instance.
*/
public AppletGrafica() {
}
}
Gianluca Coda 566/557
Pagina 112 di 131
INDEX.JSP:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>DEMO - Monitor</title>
<link rel="stylesheet" href="jquery.treeview.css">
</head>
<body>
<table style="text-align: left; width: 100%; height: 600px;"
border="0" cellpadding="2" cellspacing="2">
<tbody>
<tr align="left">
<td style="width: 100%; height: 120px;" colspan="2"
rowspan="1"><big style="font-weight:
bold;"><big>         &n
bsp;          &nbs
p;           
        QJMON Monitoraggio<br>
</big></big>
<div style="text-align: left;">
<a target="frame_menu" href="menu_job.jsp">Job
Monitoring</a>
<br> <a target="frame_menu" href="menu.jsp">Albero
classico</a>
<!-- <br> <a target="frame_menu"
href="menu_inverso.jsp">Albero inverso</a> -->
</div>
</td>
</tr>
<tr>
<td style="width: 250px; height: 460px; vertical-align:
top;">
<iframe name="frame_menu" src="menu.jsp" height="450"
width="240" frameborder="0">Contenuto
alternativo per i browser che non leggono gli iframe.
Gianluca Coda 566/557
Pagina 113 di 131
</iframe>
</td>
<td style="height: 500px; width: 100%; vertical-align:
top;"><big style="font-weight: bold;"><!--Data related to Feb 7th,
2010<br>--></big>
<iframe name="frame_centrale" src="" height="440" width=100%
frameborder="0">Contenuto
alternativo per i browser che non leggono gli iframe.
</iframe>
</td>
</tr>
</tbody>
</table>
</body>
</html>
JSP_CENTRALE.JSP:
<%@page import="java.io.File"%>
<APPLET ARCHIVE="AppletGrafica.jar, jfreechart-1.0.13.jar,jcommon1.0.16.jar,jfreechart-1.0.13-experimental.jar"
CODE="applet.AppletGrafica" width=530 height=400 ALT="You should see
an applet, not this text.">
<PARAM name=stringa value="
<%
String ext1 = ".tot";
String ext2 = ".coda";
String ext3 = ".GRconc";
String ext4 = ".gruppo";
String selectedFile = null;
String root = (new File(".")).getAbsolutePath();
//out.println(root+"<br>");
String jsp_centrale = "jsp_centrale.jsp";
root = root.substring(0, root.length() - 1) + "struttura/";
//out.println(root+"<br>");
String fileName = null;
File rootFile = new File(root+request.getParameter("folder"));
//out.println(root);
//out.println(request.getParameter("folder"));
if (rootFile.isDirectory()) {
//out.println("è una directory<br>");
for (File file : rootFile.listFiles()) {
//out.println(file+"<br>");
Gianluca Coda 566/557
Pagina 114 di 131
if (file.isFile()) {
if (file.isFile()) {
fileName = file.getName();
//out.println("fileName: "+fileName+"<br>");
//out.println(fileName.substring(fileName.length
()-ext1.length(),fileName.length()));
if (fileName.charAt(0)!='.' &&
((
(fileName.length()>ext1.length()) &&
(fileName.substring(fileName.length()ext1.length(),fileName.length())).equals(ext1)
)
||
(
(fileName.length()>ext2.length()) &&
(fileName.substring(fileName.length()ext2.length(),fileName.length())).equals(ext2)
)
||
(
(fileName.length()>ext3.length()) &&
(fileName.substring(fileName.length()ext3.length(),fileName.length())).equals(ext3)
)
||
(
(fileName.length()>ext4.length()) &&
(fileName.substring(fileName.length()ext4.length(),fileName.length())).equals(ext4)
)
)
) {
selectedFile =
request.getParameter("folder")+"/"+fileName;
out.println(selectedFile);
}
}
}
}
}
%>
">
</APPLET>
<br>
<input type="button"value="PNG" onclick="window.location.href='<
%out.print("http://143.225.93.195:8080/definitivo/"+selectedFile+".p
ng");%>'">
Gianluca Coda 566/557
Pagina 115 di 131
<input type="button"value="JPEG" onclick="window.location.href='<
%out.print("http://143.225.93.195:8080/definitivo/"+selectedFile+".j
pg");%>'">
<input type="button"value="PDF" onclick="window.location.href='<
%out.print("http://143.225.93.195:8080/definitivo/"+selectedFile+".p
df");%>'">
<input type="button"value="SVG" onclick="window.location.href='<
%out.print("http://143.225.93.195:8080/definitivo/"+selectedFile+".s
vg");%>'">
JSP_CENTRALE_INVERSO.JSP:
<%@page import="java.io.File"%>
<APPLET ARCHIVE="AppletGrafica.jar, jfreechart-1.0.13.jar,jcommon1.0.16.jar,jfreechart-1.0.13-experimental.jar"
CODE="applet.AppletGrafica" width=530 height=400 ALT="You should see
an applet, not this text.">
<PARAM name=stringa value="
<%
String selectedFile = null;
String root = (new File(".")).getAbsolutePath();
//out.println(root+"<br>");
String jsp_centrale = "jsp_centrale.jsp";
root = root.substring(0, root.length() - 1) + "struttura/";
File dataFile = new File(request.getParameter("dataFile"));
out.println(dataFile);
%>
">
</APPLET>
<br>
<input type="button"value="PNG" onclick="window.location.href='<
%out.print("http://143.225.93.195:8080/definitivo/"+dataFile+".png")
;%>'">
<input type="button"value="JPEG" onclick="window.location.href='<
%out.print("http://143.225.93.195:8080/definitivo/"+dataFile+".jpg")
;%>'">
<input type="button"value="PDF" onclick="window.location.href='<
Gianluca Coda 566/557
Pagina 116 di 131
%out.print("http://143.225.93.195:8080/definitivo/"+dataFile+".pdf")
;%>'">
<input type="button"value="SVG" onclick="window.location.href='<
%out.print("http://143.225.93.195:8080/definitivo/"+dataFile+".svg")
;%>'">
MENU_JOB.JSP:
<link rel="stylesheet" href="jquery.treeview.css">
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js
"></script>
<script src="jquery.cookie.js" type="text/javascript"></script>
<script src="jquery.treeview.js" type="text/javascript"></script>
<script type="text/javascript" src="demo.js"></script>
<ul id="red" class="treeview-red">
<li><a target="frame_centrale"
href="http://143.225.93.195:8080/Tirocinio/atlas.coda.jsp"><span>atl
as</span></a>
<ul>
<li><a target="frame_centrale"
href="http://143.225.93.195:8080/Tirocinio/atlas.atlas.vo.jsp"><span
>atlas VO</span></a>
</li>
<li><a target="frame_centrale"
href="http://143.225.93.195:8080/Tirocinio/other.atlas.vo.jsp"><span
>other</span></a></li>
</ul>
Gianluca Coda 566/557
Pagina 117 di 131
</li>
<li><a target="frame_centrale"
href="http://143.225.93.195:8080/Tirocinio/egee_long.coda.jsp"><span
>egee_long</span></a>
<ul>
<li><a target="frame_centrale"
href="http://143.225.93.195:8080/Tirocinio/argo.egee_long.vo.jsp"><s
pan>argo VO</span></a></li>
<li><a target="frame_centrale"
href="http://143.225.93.195:8080/Tirocinio/biomed.egee_long.vo.jsp">
<span>biomed VO</span></a></li>
<li><a target="frame_centrale"
href="http://143.225.93.195:8080/Tirocinio/gilda.egee_long.vo.jsp"><
span>gilda VO</span></a></li>
<li><a target="frame_centrale"
href="http://143.225.93.195:8080/Tirocinio/superbvo.egee_long.vo.jsp
"><span>superbvo.org VO</span></a></li>
<li><a target="frame_centrale"
href="http://143.225.93.195:8080/Tirocinio/other.egee_long.vo.jsp"><
span>other</span></a></li>
</ul>
</li>
<li><a target="frame_centrale"
href="http://143.225.93.195:8080/Tirocinio/egee_short.coda.jsp"><spa
n>egee_short</span></a>
Gianluca Coda 566/557
Pagina 118 di 131
<ul>
<li><a target="frame_centrale"
href="http://143.225.93.195:8080/Tirocinio/argo.egee_short.vo.jsp"><
span>argo VO</span></a></li>
<li><a target="frame_centrale"
href="http://143.225.93.195:8080/Tirocinio/biomed.egee_short.vo.jsp"
><span>biomed VO</span></a></li>
<li><a target="frame_centrale"
href="http://143.225.93.195:8080/Tirocinio/gilda.egee_short.vo.jsp">
<span>gilda VO</span></a></li>
<li><a target="frame_centrale"
href="http://143.225.93.195:8080/Tirocinio/other.egee_short.vo.jsp">
<span>other</span></a></li>
</ul>
</li>
<li><a target="frame_centrale"
href="http://143.225.93.195:8080/Tirocinio/grisu_long.coda.jsp"><spa
n>grisu_long</span></a>
<ul>
<li><a target="frame_centrale"
href="http://143.225.93.195:8080/Tirocinio/argo.grisu_long.vo.jsp"><
span>argo VO</span></a></li>
<li><a target="frame_centrale"
href="http://143.225.93.195:8080/Tirocinio/gilda.grisu_long.vo.jsp">
<span>gilda VO</span></a>
Gianluca Coda 566/557
Pagina 119 di 131
<li><a target="frame_centrale"
href="http://143.225.93.195:8080/Tirocinio/other.grisu_long.vo.jsp">
<span>other</span></a></li>
</ul>
</li>
<li><a target="frame_centrale"
href="http://143.225.93.195:8080/Tirocinio/grisu_short.coda.jsp"><sp
an>grisu_short</span></a>
<ul>
<li><a target="frame_centrale"
href="http://143.225.93.195:8080/Tirocinio/gilda.grisu_short.vo.jsp"
><span>gilda VO</span></a></li>
<li><a target="frame_centrale"
href="http://143.225.93.195:8080/Tirocinio/other.grisu_short.vo.jsp"
><span>other</span></a></li>
</ul>
<li><a target="frame_centrale"
href="http://143.225.93.195:8080/Tirocinio/unina_long.coda.jsp"><spa
n>unina_long</span></a>
<ul>
<li><a target="frame_centrale"
href="http://143.225.93.195:8080/Tirocinio/unina.unina_long.vo.jsp">
<span>unina.it VO</span></a></li>
<li><a target="frame_centrale"
href="http://143.225.93.195:8080/Tirocinio/other.unina_long.vo.jsp">
<span>other</span></a></li>
Gianluca Coda 566/557
Pagina 120 di 131
</ul>
</li>
</ul>
MENU.JSP:
<link rel="stylesheet" href="jquery.treeview.css">
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js
"></script>
<script src="jquery.cookie.js" type="text/javascript"></script>
<script src="jquery.treeview.js" type="text/javascript"></script>
<script type="text/javascript" src="demo.js"></script>
<ul id="red" class="treeview-red">
<%@page import="java.io.File"%>
<%@page import="java.util.LinkedList"%>
<%@page import="java.util.Arrays"%>
<%
String root = (new File(".")).getAbsolutePath();
String jsp_centrale = "jsp_centrale.jsp";
root = root.substring(0, root.length() - 1) + "struttura/";
File dir = new File(root);
File[] listFile = dir.listFiles();
if (listFile != null && listFile.length > 0) {
for (File file : listFile) {
if (!(file.getName().charAt(0) == '.') &&
file.isDirectory()) {
//out.println("<li><a target=\"frame_centrale\" href=\""
+ jsp_centrale + "?folder=" + file + "\"><span>" + file.getName() +
"</span></a></li>");
out.println("<li><a target=\"frame_centrale\" href=\"" +
jsp_centrale + "?folder=" + file.getName() + "\"><span>" +
file.getName() + "</span></a>");
out.println("<ul>");
File[] firstListFiles = file.listFiles();
Arrays.sort(firstListFiles, 0, firstListFiles.length);
for (File firstLevelFile : firstListFiles) {
if (firstLevelFile.isDirectory()) {
out.println("<li><a target=\"frame_centrale\"
href=\"" + jsp_centrale + "?folder=" + file.getName()
Gianluca Coda 566/557
Pagina 121 di 131
+"/"+firstLevelFile.getName() + "\"><span>" +
firstLevelFile.getName() + "</span></a>");
out.println("<ul>");
File[] secondListFiles =
firstLevelFile.listFiles();
Arrays.sort(secondListFiles, 0,
secondListFiles.length);
for (File secondLevelFile : secondListFiles) {
if (secondLevelFile.isDirectory()) {
out.println("<li><a
target=\"frame_centrale\" href=\"" + jsp_centrale + "?folder=" +
file.getName()+"/"+firstLevelFile.getName() +
"/"+secondLevelFile.getName() + "\"><span>" +
secondLevelFile.getName() + "</span></a>");
out.println("<ul>");
File[] thirdListFiles =
secondLevelFile.listFiles();
Arrays.sort(thirdListFiles, 0,
thirdListFiles.length);
for (File thirdLevelFile :
thirdListFiles) {
if (thirdLevelFile.isDirectory()) {
out.println("<li><a
target=\"frame_centrale\" href=\"" + jsp_centrale + "?folder=" +
file.getName()+"/"+firstLevelFile.getName() +
"/"+secondLevelFile.getName()+ "/"+thirdLevelFile.getName() +
"\"><span>" + thirdLevelFile.getName() + "</span></a></li>");
//out.println("<ul>");
//for (File
fourthLevelFile : thirdLevelFile.listFiles())
//if
(fourthLevelFile.isDirectory())
//out.println("</li></ul>");
}//IF5
}//FOR4
out.println("</li></ul>");
}//IF4
}//FOR3
out.println("</li></ul>");
}//IF3
}//FOR2
out.println("</li></ul>");
}//IF2
}//FOR1
} //IF1
%>
</ul>
Gianluca Coda 566/557
Pagina 122 di 131
MENU_INVERSO.JSP:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1" import="java.sql.*" import="bean.*"
import="java.util.*"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO8859-1">
<jsp:useBean id="DBJ" class="bean.Job" scope="session"/>
<jsp:useBean id="DBJV" class="bean.JobView" scope="session"/>
<title>View Vo</title>
</head>
<body>
<link rel="stylesheet" href="jquery.treeview.css">
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js
"></script>
<script src="jquery.cookie.js" type="text/javascript"></script>
<script src="jquery.treeview.js" type="text/javascript"></script>
<script type="text/javascript" src="demo.js"></script>
<ul id="red" class="treeview-red">
<%@page
<%@page
<%@page
<%@page
<%@page
import="java.io.File"%>
import="java.util.LinkedList"%>
import="java.util.Arrays"%>
import="java.util.HashMap"%>
import="java.util.Iterator"%>
<%
String root = (new File(".")).getAbsolutePath();
String jsp_centrale = "jsp_centrale_inverso.jsp";
root = root.substring(0, root.length() - 1) + "struttura/";
File dir = new File(root);
File[] listFile = dir.listFiles();
// se la struttura delle cartelle non è vuota
if (listFile != null && listFile.length > 0) {
HashMap<String, LinkedList<String>> voCodeMap = null; // mappa
contenente tutte le VO e per ognuna di esse la lista delle code
Gianluca Coda 566/557
Pagina 123 di 131
sulle quali è presente
// (String: PathName della cartella della VO,
LinkedList<String>: lista dei PathName delle cartelle delle code)
// ciclo su file-cartelle della struttura
for (File file : listFile) {
// se è una sottocartella della struttura (giornalieri,
settimanali, ...)
voCodeMap = new HashMap<String, LinkedList<String>>(); // nuova
mappa per la sottocartella della struttura in esame (giornalieri,
settimanali, ...)
if (!(file.getName().charAt(0) == '.') && file.isDirectory()) {
// inserimento voce menu di primo livello (giornalieri,
settimanali, ....)
out.println("<li><a target=\"frame_centrale\" href=\"" +
jsp_centrale + "?dataFile=" + file.getName() + "/" + file.getName()
+ ".tot" + "\"><span>" + file.getName() + "</span></a>");
out.println("<ul>");
File[] firstListFiles = file.listFiles();
Arrays.sort(firstListFiles, 0, firstListFiles.length);
// ciclo sul contenuto delle cartelle di primo livello
for (File firstLevelFile : firstListFiles) {
// per ogni cartella delle code
if (firstLevelFile.isDirectory()) {
//String codaDirPathName = file.getName()
+"/"+firstLevelFile.getName(); // pathname della cartella della coda
String codaName = firstLevelFile.getName(); //
nome della coda
File[] secondListFiles =
firstLevelFile.listFiles();
Arrays.sort(secondListFiles, 0,
secondListFiles.length);
// ciclo sul contenuto delle cartelle di secondo
livello (code)
for (File secondLevelFile : secondListFiles)
{
// per ogni cartella delle VO
if (secondLevelFile.isDirectory()) {
LinkedList<String> codeList =
voCodeMap.remove(secondLevelFile.getName());
if (codeList == null)
codeList = new
LinkedList<String>();
codeList.add(codaName);
voCodeMap.put(secondLevelFile.getName(), codeList);
}//IF4
}//FOR3
}//IF3
Gianluca Coda 566/557
Pagina 124 di 131
}//FOR2
Iterator keysIterator = voCodeMap.keySet().iterator();
while (keysIterator.hasNext()){
String key = (String) keysIterator.next();
out.println("<li><a target=\"frame_centrale\"
href=\"" + jsp_centrale + "?dataFile=" + file.getName() + "/" + key
+ ".vo.VOconc" + "\"><span>" + key + "</span></a>");
out.println("<ul>");
LinkedList<String> codeKeys = voCodeMap.get(key);
for(String coda : codeKeys)
out.println("<li><a target=\"frame_centrale\"
href=\"" + jsp_centrale + "?dataFile=" + file.getName() + "/" + coda
+ "/" + key + "/" + key + ".vo" + "\"><span>" + coda + "</span></a>"
);
out.println("</ul></li>"); // chiusura tag seconda
voce (VO)
}
out.println("</li></ul>"); // chiusura tag prima voce
(giornalieri, settimanali, ...)
}//IF2
}//FOR1
}//IF1
%>
</ul>
JSP JOB MONITORING VO:
<% ResultSet rs=DBJV.GetJobRunVo("atlas","atlas");
//Job in running sul sistema
%>
<center><table border="1">
<tr><th>User</th>
<th>JOB ID</th>
<th>Submitted<br>from</th>
<th>Running on<br>(slots/RAM/KSI)</th>
<th>Start<br>running</th>
<th>Collecting<br>time</th>
<th>WCT<br>hh:mm:ss</th>
<th>CPU Time<br>hh:mm:ss</th>
<th>CPU/WCT<br>%(new/old)</th>
<th>RSS<br>MBytes</th>
Gianluca Coda 566/557
Pagina 125 di 131
<th>Virtual<br>MBytes</th></tr>
<% while(rs.next()){%>
<tr><td align="center"><%=rs.getString("User")%> </td>
<td align="center"><%=rs.getString("JobId")%> </td>
<%if (rs.getString("StatusPBS")==null){ %>
<td align="center"><%=rs.getString("L_From_Host")%></td>
<td align="center"><%=rs.getString("L_Exec_Host")%>, <
%=rs.getString("MEM")%>,?</td>
<td align="center"><%=rs.getString("L_Submit_time")%></td>
<td align="center" ><%=rs.getString("TimeC")%></td>
<td align="center" ><%=rs.getString("WCT")%></td>
<td align="center"><%=rs.getString("CPUTime")%></td>
<td align="center" >?</td>
<td align="center" >?</td>
<td align="center" ><%=rs.getString("Vmem")%></td>
<%}else{ %>
<td align="center"><%=rs.getString("P_From_Host")%></td>
<td align="center"><%=rs.getString("P_WN")%>,<%=rs.getString("MEM")
%>,?</td>
<td align="center"><%=rs.getString("TimeR")%></td>
<td align="center" ><%=rs.getString("TimeC")%></td>
<td align="center" ><%=rs.getString("WCT")%></td>
<td align="center"><%=rs.getString("CPUTime")%></td>
<td align="center" >?</td>
<td align="center" >?</td>
<td align="center" ><%=rs.getString("Vmem")%></td>
<%} %>
</tr>
Gianluca Coda 566/557
Pagina 126 di 131
<%} DBSupport.setClose(rs);%>
</table></center>
</body>
</html>
JSP JOB MONITORING CODA:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1" import="java.sql.*" import="bean.*"
import="java.util.*"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO8859-1">
<jsp:useBean id="DBJ" class="bean.Job" scope="session"/>
<jsp:useBean id="DBJV" class="bean.JobView" scope="session"/>
<title>View Coda</title>
</head>
<body>
<% ResultSet rs=DBJV.GetJobCoda("atlas");
//Job in running sul sistema
%>
<center><table border="1">
<tr><th>User</th>
<th>JOB ID</th>
<th>Vo</th>
Gianluca Coda 566/557
Pagina 127 di 131
<th>Submitted<br>from</th>
<th>Running on<br>(slots/RAM/KSI)</th>
<th>Start<br>running</th>
<th>Collecting<br>time</th>
<th>WCT<br>hh:mm:ss</th>
<th>CPU Time<br>hh:mm:ss</th>
<th>CPU/WCT<br>%(new/old)</th>
<th>RSS<br>MBytes</th>
<th>Virtual<br>MBytes</th></tr>
<% while(rs.next()){%>
<tr><td align="center"><%=rs.getString("User")%> </td>
<td align="center"><%=rs.getString("JobId")%> </td>
<%if (rs.getString("NomeVo")==null){ %>
<td width="15%"> Local </td>
<% }else {%>
<td width="15%"> <
%=rs.getString("NomeVo")%> </td>
<%} %>
<%if (rs.getString("StatusPBS")==null){ %>
<td align="center"><%=rs.getString("L_From_Host")%></td>
<td align="center"><%=rs.getString("L_Exec_Host")%>, <
%=rs.getString("MEM")%>,?</td>
<td align="center"><%=rs.getString("L_Submit_time")%></td>
<td align="center" ><%=rs.getString("TimeC")%></td>
<td align="center" ><%=rs.getString("WCT")%></td>
<td align="center"><%=rs.getString("CPUTime")%></td>
<td align="center" >?</td>
<td align="center" >?</td>
<td align="center" ><%=rs.getString("Vmem")%></td>
<%}else{ %>
<td align="center"><%=rs.getString("P_From_Host")%></td>
<td align="center"><%=rs.getString("P_WN")%>,<%=rs.getString("MEM")
%>,?</td>
<td align="center"><%=rs.getString("TimeR")%></td>
<td align="center" ><%=rs.getString("TimeC")%></td>
Gianluca Coda 566/557
Pagina 128 di 131
<td
<td
<td
<td
<td
align="center" ><%=rs.getString("WCT")%></td>
align="center"><%=rs.getString("CPUTime")%></td>
align="center" >?</td>
align="center" >?</td>
align="center" ><%=rs.getString("Vmem")%></td>
<%} %>
</tr>
<%} DBSupport.setClose(rs);%>
</table></center>
</body>
</html>
JSP JOB MONITORING OTHER:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1" import="java.sql.*" import="bean.*"
import="java.util.*"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO8859-1">
<jsp:useBean id="DBJ" class="bean.Job" scope="session"/>
<jsp:useBean id="DBJV" class="bean.JobView" scope="session"/>
<title>View Vo</title>
</head>
<body>
Gianluca Coda 566/557
Pagina 129 di 131
<% ResultSet rs=DBJV.GetJobRunOtherCoda("atlas");
//Job in running sul sistema
%>
<center><table border="1">
<tr><th>User</th>
<th>JOB ID</th>
<th>Submitted<br>from</th>
<th>Running on<br>(slots/RAM/KSI)</th>
<th>Start<br>running</th>
<th>Collecting<br>time</th>
<th>WCT<br>hh:mm:ss</th>
<th>CPU Time<br>hh:mm:ss</th>
<th>CPU/WCT<br>%(new/old)</th>
<th>RSS<br>MBytes</th>
<th>Virtual<br>MBytes</th></tr>
<% while(rs.next()){%>
<tr><td align="center"><%=rs.getString("User")%> </td>
<td align="center"><%=rs.getString("JobId")%> </td>
<%if (rs.getString("StatusPBS")==null){ %>
<td align="center"><%=rs.getString("L_From_Host")%></td>
<td align="center"><%=rs.getString("L_Exec_Host")%>, <
%=rs.getString("MEM")%>,?</td>
<td align="center"><%=rs.getString("L_Submit_time")%></td>
<td align="center" ><%=rs.getString("TimeC")%></td>
<td align="center" ><%=rs.getString("WCT")%></td>
<td align="center"><%=rs.getString("CPUTime")%></td>
<td align="center" >?</td>
<td align="center" >?</td>
<td align="center" ><%=rs.getString("Vmem")%></td>
<%}else{ %>
<td align="center"><%=rs.getString("P_From_Host")%></td>
<td align="center"><%=rs.getString("P_WN")%>,<%=rs.getString("MEM")
Gianluca Coda 566/557
Pagina 130 di 131
%>,?</td>
<td align="center"><%=rs.getString("TimeR")%></td>
<td align="center" ><%=rs.getString("TimeC")%></td>
<td align="center" ><%=rs.getString("WCT")%></td>
<td align="center"><%=rs.getString("CPUTime")%></td>
<td align="center" >?</td>
<td align="center" >?</td>
<td align="center" ><%=rs.getString("Vmem")%></td>
<%} %>
</tr>
<%} DBSupport.setClose(rs);%>
</table></center>
</body>
</html>
Gianluca Coda 566/557
Pagina 131 di 131