• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Un Framework per la valutazione delle statistiche di esercizio della rete wireless di Ateneo "Wifi-Unina"
 

Un Framework per la valutazione delle statistiche di esercizio della rete wireless di Ateneo "Wifi-Unina"

on

  • 1,894 views

Un Framework per la valutazione delle statistiche di esercizio della rete wireless di Ateneo "Wifi-Unina"

Un Framework per la valutazione delle statistiche di esercizio della rete wireless di Ateneo "Wifi-Unina"

Statistics

Views

Total Views
1,894
Views on SlideShare
1,881
Embed Views
13

Actions

Likes
0
Downloads
0
Comments
0

1 Embed 13

http://mygarbagecollector.org 13

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Un Framework per la valutazione delle statistiche di esercizio della rete wireless di Ateneo "Wifi-Unina" Un Framework per la valutazione delle statistiche di esercizio della rete wireless di Ateneo "Wifi-Unina" Document Transcript

    • Università degli Studi di Napoli Federico II Facoltà di Scienze MM.FF.NN. Corso di Laurea in Informatica Tesi Sperimentale di Laurea TriennaleUn Framework per la valutazione delle statistiche di esercizio della rete wireless di Ateneo “Wifi-Unina” Relatori CandidatoProf. Guido Russo Paolo VanacoreDr. Ing Catello Di Martino Matricola: 566/1539 Anno accademico 2009/2010
    • Desidero ringraziare... ...il Prof Guido Russo e lIng. Catello Di Martino per avermi consentito di svolgere questo lavoro di tesi e per il costante supporto umano e professionale, ...la mia famiglia ed in particolare i miei genitori per il sostegno e la fiducia che mi hanno consentito di intraprendere questo percorso, ...Paola per avermi sostenuto in ogni attimo, anche nei momenti più difficili, ...tutti gli amici del corso di studi, dello SCoPE e di vita.Paolo Vanacore 566/1539 Pagina 2 di 279
    • Indice generale1 Introduzione..........................................................................................................................52 La rete wireless di Ateneo: “Wifi-Unina”.............................................................................7 2.1 Topologia Di Rete..........................................................................................................7 2.2 Apparati Di Rete..........................................................................................................10 2.3 Dati Generali Sullinfrastruttura Di Rete Wireless......................................................17 2.3.1 Infrastruttura di Monte SantAngelo..................................................................21 2.3.2 Infrastruttura del Centro Storico........................................................................22 2.3.3 Infrastruttura del Policlinico..............................................................................243 Monitoraggio di rete............................................................................................................26 3.1 Il Protocollo SNMP: Simple Network Management Protocol....................................27 3.2 Cacti.............................................................................................................................32 3.3 RRDTool: Round-Robin Database Tool......................................................................364 Lapplicazione realizzata.....................................................................................................46 4.1 Requisiti ......................................................................................................................46 4.2 Architettura Generale..................................................................................................49 4.3 Accesso Ai Dati Di Monitoraggio...............................................................................51 4.3.1 Server di monitoraggio: Il Data Server..............................................................52 4.3.2 Il Data Client.....................................................................................................54 4.3.2.1 Parsing di XML dump file.....................................................................54 4.3.2.2 Il database RRDB..................................................................................56 4.4 Logica Di Controllo Per La Gestione Dei Dati...........................................................60 4.4.1 Servizi di amministrazione dei dati...................................................................61 4.4.2 Temporizzazione delle letture degli rrd.............................................................62 4.4.3 Monitor e Report Statistici: il Design Pattern Observer....................................64 4.5 Presentazione Dei Dati................................................................................................66 4.5.1 Model 1..............................................................................................................67 4.5.2 Model 2 e Design Pattern MVC........................................................................69 4.5.3 JFreeChart..........................................................................................................73 4.6 Architettura Completa.................................................................................................765 Guida duso dellapplicazione realizzata.............................................................................77 5.1 Interfaccia Di Amministrazione..................................................................................77 5.1.1 Gestione dei Data Server...................................................................................81 5.1.2 Gestione dei Report statistici.............................................................................85 5.1.3 Le briciole di pane.............................................................................................86 5.2 Interfaccia Di Visualizzazione Dei Grafici..................................................................876 Considerazioni e conclusioni..............................................................................................917 Appendici............................................................................................................................93 7.1 Messa In Esercizio Del Framework............................................................................93 7.1.1 Data Server........................................................................................................93 7.1.2 Data Client.........................................................................................................95Paolo Vanacore 566/1539 Pagina 3 di 279
    • 7.1.3 Interfaccia di amministrazione..........................................................................96 7.1.4 Interfaccia di visualizzazione dei grafici...........................................................97 7.2 Diagrammi...................................................................................................................99 7.2.1 UML – Use Case Diagrams...............................................................................99 7.2.2 UML – Component Diagrams.........................................................................100 7.2.3 UML – Class Diagrams...................................................................................101 7.2.4 UML – Sequence Diagrams.............................................................................111 7.2.5 UML – Statechart.............................................................................................114 7.2.6 EER Diagram...................................................................................................115 7.3 Documentazione JavaDoc.........................................................................................116 7.4 Codice Sorgente.........................................................................................................116 7.4.1 it.unina.scope.wistat.dataclient........................................................................116 7.4.2 it.unina.scope.wistat.dataclient.database.........................................................136 7.4.3 it.unina.scope.wistat.dataclient.net..................................................................144 7.4.4 it.unina.scope.wistat.dataclient.rrd..................................................................162 7.4.5 Files di configurazione DataClient..................................................................170 7.4.6 it.unina.scope.wistat.dataserver.......................................................................171 7.4.7 it.unina.scope.wistat.dataserver.database.........................................................175 7.4.8 it.unina.scope.wistat.dataserver.net.................................................................176 7.4.9 Files di configurazione DataServer.................................................................183 7.4.10 Script SQL per la creazione del database rrdb...............................................184 7.4.11 WiStat – bean.................................................................................................192 7.4.12 WiStat – controller (Servlet)..........................................................................202 7.4.13 Wistat – database...........................................................................................206 7.4.14 WiStat – JSP..................................................................................................210 7.4.15 Files di configurazione dellinterfaccia WiStat..............................................214 7.4.16 WiStatAdmin – bean......................................................................................216 7.4.17 WiStatAdmin – controller (Servlet)...............................................................225 7.4.18 WiStatAdmin – JSP.......................................................................................250 7.4.19 Files di configurazione dellinterfaccia WiStatAdmin...................................2748 Bibliografia e Sitografia....................................................................................................278Paolo Vanacore 566/1539 Pagina 4 di 279
    • 1 IntroduzioneUna corretta valutazione dello stato di un sistema complesso è alla base del processo dimanutenzione, gestione ed evoluzione del sistema stesso. Ne consegue la necessità difornire adeguati strumenti che ne consentano valutazioni corrette.Il monitoraggio, inteso come strumento di rappresentazione dello stato di un sistema,svolge, quindi, un ruolo di primaria importanza per la vita ed evoluzione del sistemastesso.In tale contesto il sistema è rappresentato dalla rete wireless di Ateneo “WiFi-Unina” egli strumenti da realizzare consistono in un framework per la valutazione dellestatistiche di esercizio della stessa.Su tali considerazioni si basa il lavoro di tesi che si colloca nellambito delliniziativa“WiFi SUD” del progetto “ICT4University” che realizza quanto previsto dallobiettivoUniversità del Piano E-Gov 2012. In particolare liniziativa ha previsto ilfinanziamento di progetti delle Università del Sud per realizzare, estendere ocompletare reti di connettività senza fili e sviluppare servizi online di tipoamministrativo e/o didattico, accessibili gratuitamente da parte degli studenti.Il framework realizzato consta di due principali sottosistemi: • il sottosistema di monitoraggio per la raccolta di informazioni sugli apparati di rete; • il sottosistema per la definizione e la rappresentazione di statistiche.Per il monitoraggio è stato utilizzato il software open source Cacti. Tale applicativocostituisce un sistema completo per il monitoraggio passivo di apparati di rete,offrendo tutti gli strumenti necessari per interrogazioni SNMP (Simple NetworkManagement Protocol).Per quanto riguarda il sottosistema per le statistiche, è stata realizzata unapplicazioneche consente, attraverso interfaccia web, di definire report statistici a partire dai dati Paolo Vanacore 566/1539 Pagina 5 di 279
    • frutto di monitoraggio. Lapplicazione ha unarchitettura client/server multithread e ciòconsente di avere uno o più server di monitoraggio con una gestione centralizzata deidati di interesse.Tra le problematiche affrontate le più rilevanti riguardano laccesso ai dati dimonitoraggio e la gestione di report statistici.Laccesso ai dati ha richiesto lo studio di uno degli strumenti software open sourcemaggiormente utilizzati nellambito del monitoraggio di sistemi in genere, del qualeCacti è considerato una GUI user friendly: RRDTool. Buona parte del data layer delframework realizzato riguarda proprio linterazione con RRDTool, al fine di replicare idati di monitoraggio in un database realizzato su DBMS MySQL e poterli cosìconsolidare per mezzo di funzioni statistiche. Particolare attenzione è stata data,quindi, allaccesso, coerenza e persistenza dei dati di monitoraggio.Lapplicazione per le statistiche è interamente scritta in linguaggio Java per consentireunalta portabilità.Tra le principali tecnologie adottate vi sono: • Parser Document Object Model, istruzioni XPath e parser Simple API for XML per i files XML; • Java DataBase Connectivity per le connessioni ai database MySQL; • Java Server Pages, Servlet e JavaBeans per la presentazione dei dati; • Libreria JFreeChart per la creazione di grafici. Paolo Vanacore 566/1539 Pagina 6 di 279
    • 2 La rete wireless di Ateneo: “Wifi-Unina” 2.1 Topologia di reteSeguendo un approccio top-down nella descrizione della topologia di rete, una primaclassificazione si basa sulle principali sedi di Ateneo che costituiscono tre sotto-domini(fig. 2.1.1): • Monte SantAngelo; • Centro Storico; • Policlinico. Fig. 2.1.1 – le tre principali sedi di Ateneo (immagine ottenuta da Google Eearth ). Paolo Vanacore 566/1539 Pagina 7 di 279
    • Queste sedi sono interconnesse per mezzo della rete metropolitana (MAN –Metropolitan Area Network) che, attraverso un cablaggio in fibra ottica, offrecollegamenti a 2.4 Gigabit (Packet over SONET – Synchronous Optical NETwork).Scendendo nella gerarchia e considerando unicamente i nodi di interesse, unadescrizione più dettagliata è data dalla suddivisione in strutture e facoltà (fig. 2.1.2). Centri Comuni Aulario A Monte SantAngelo Dipartimento di Chimica Dipartimento di Matematica Biblioteche Agnano Edificio Edificio 1 Via Claudio Edificio 3 Ingegneria Edificio 5 Piazzale Tecchio Edificio Mezzocannone Centro Storico S.Antoniello Edificio 01 Edificio 04 Edificio 05 Edificio 08 Edificio 09 Edificio 10 Edificio 11 Edificio 12 Policlinico Edificio 13 Edificio 14/15 Edificio 17 Edificio 18 Edificio 19 Edificio 20 Edificio 21 Ed. 22 (Mensa) Fig. 2.1.2 – schema gerarchico della topologia logica di rete in basato sulle sedi Paolo Vanacore 566/1539 Pagina 8 di 279
    • Per non appesantire lo schema precedente sono state omesse le ulteriori classificazionidelle strutture in piani/livelli derivanti dal cablaggio strutturato.Come si evince dalla fig. 2.1.2, la sede di Monte SantAngelo costituisce il nodoprincipale della rete. Il POP (Point Of Presence – punto di connessione fisica tra retidi telecomunicazione) di Monte SantAngelo, infatti, offre e gestisce laccesso da everso diverse reti e servizi, con connessioni da 1GbE fino a 10GbE, tra cui: • accesso alla rete GARR Rete Italiana per la ricerca nata nel 1977 e gestita dal Consortium GARR (Gruppo per lArmonizzazione delle Reti della Ricerca). Diversi sono gli enti che afferiscono a tale consorzio, tra cui i fondatori: ▪ CNR (Consiglio Nazionale delle Ricerche); ▪ ENEA (Ente per le Nuove Teconologie, lEnergia e lAmbiente); ▪ INFN (Istituto Nazionale di Fisica Nucleare); ▪ Fondazione CRUI (Conferenza dei Rettori delle Università Italiane) in rappresentanza delle Università Italiane. • griglie computazionali (GRID): ▪ SCOPE (Sistema Cooperativo distribuito ad alte Prestazioni per Elaborazioni scientifiche multidisciplinari – infrastruttura di supercomputing general purpose basata su GRID e calcolo distribuito in genere); ▪ GRISU (Griglia del Sud – infrastruttura distribuita a carattere multidisciplinare); ▪ ATLAS (griglia nata nellambito dellesperimento A Toroidal LHC Apparatus presso lacceleratore Large Hadron Collider del CERN di Ginevra). Paolo Vanacore 566/1539 Pagina 9 di 279
    • Limitando il discorso alla rete wireless di Ateneo, considerata la complessità e lavastità della stessa, un aspetto particolarmente importante, dal punto di vistaprogettuale, è sicuramente la scalabilità.Nei successivi paragrafi vengono descritte le soluzioni architetturali adottateevidenziando come queste ultime sostengono tale caratteristica.In particolare vengono considerati i seguenti tipi di scalabilità: • scalabilità di carico Capacità di scalare sul carico, inteso come mole di traffico/numero di utenti; • scalabilità geografica Capacità di estensione fisica della rete; • scalabilità amministrativa Capacità di mantenere inalterata la gestibilità allevolversi della rete. 2.2 Apparati di reteOgnuna delle tre principali sedi di Ateneo (Monte SantAngelo, Centro Storico ePoliclinico) costituisce un sotto-dominio della rete.La totalità degli apparati sono prodotti dalla Cisco ed offrono una soluzione completaper la realizzazione e gestione di reti WLAN (Wireless Local Area Network). Inparticolare, considerando ogni sotto-dominio come una WLAN autonoma,larchitetturaadottata è gerarchica (fig. 2.2.1) e costituita da tre principali tipologie di apparati: • WLSE (Wireless Lan Solution Engine); • WDS (Wireless Domain Service); • AP (Access Point).Paolo Vanacore 566/1539 Pagina 10 di 279
    • WLSE sottodominio i WDS1 WDS2 WDSn Infrastructure APs  Infrastructure APs  Infrastructure APs  (registered on WDS 1) (registered on WDS 2) (registered on WDS n)AP1 AP2 APx AP1 AP2 APy AP1 AP2 APz Fig. 2.2.1 – apparati attivi di un generico sotto-dominio di reteTale soluzione architetturale è conosciuta con il nome di “Cisco SWAN” (StructuredWireless-Aware Network). Il programma SWAN della Cisco mira ad integrare varicomponenti di rete al fine di fornire WLAN di qualità.Gli obiettivi, dichiarati dalla Cisco, di tale programma, sono principalmente i seguenti: • Integrazione dei servizi wired e wireless per mezzo di infrastrutture sia hardware che software (Cisco IOS Software) proprietarie; • Semplificazione della gestione di numerosi punti daccesso, consentendo un accesso centralizzato e da remoto; • Monitoraggio e scansione di radio frequenze; • Alta disponibilità della LAN (Local Area Network) per mezzo di processi di auto-diagnosi e “self-healing” (auto-guarigione) come la rilevazione, individuazione ed isolamento di interferenze di rete; • Gestione dei servizi di autenticazione ed autorizzazione secondo lo standard IEEE 802.1X. In particolare tale aspetto è garantito da un server RADIUSPaolo Vanacore 566/1539 Pagina 11 di 279
    • (Remote Authentication Dial-In User Service). RADIUS è un protocollo del tipo AAA (Authentication Authorization Accounting) con il compito, quindi, di realizzare le tre funzioni di: ▪ autenticazione (authentication); ▪ controllo degli accessi (authorization); ▪ tracciamento del consumo delle risorse da parte degli utenti (accounting).Come si evince dalla figura 2.2.1, ogni sotto-dominio i della rete è dotato di un WLSE(fig. 2.2.2). Il WLSE può essere paragonato ad un vero e proprio server che offremolteplici servizi di gestione per tutti gli apparati del sotto-dominio a suo carico. Inparticolare, le caratteristiche principali del WLSE sono le seguenti: • gestione centralizzata della WLAN; • rilevamento ed individuazione di connessioni non autorizzate (Intrusion Detection); • rilevamento di interferenze radio; • monitoraggio delle prestazioni (Reports); • sistema di configurazione dei punti daccesso automatizzato. Fig. 2.2.2 – esempio di Cisco WLSE 1130In figura 2.2.3 è riportata una schermata dellinterfaccia web del WLSE di MonteSantAngelo dalla quale è possibile notare la mole di funzionalità offerte che spazianoPaolo Vanacore 566/1539 Pagina 12 di 279
    • dai servizi di configurazione a quelli di monitoraggio ed allarmistica.Per una gestione ancor più completa dellintera WLAN, è degno di nota il “LocationManager”. Tale applicazione, accessibile sempre dallinterfaccia web del WLSE, sipresenta come un applet JAVA che consente, previa configurazione, di visualizzare leplanimetrie delle strutture che ospitano la WLAN, la precisa ubicazione e gli stati diesercizio di ogni singolo apparato (fig. 2.2.4). Fig. 2.2.3 – interfaccia web del WLSE di Monte SantAngeloPaolo Vanacore 566/1539 Pagina 13 di 279
    • Fig. 2.2.4 – il Location Manager del WLSE di Monte SantAngelo. A destra la planimetria del Livello 0 dei Centri Comuni con lesatta ubicazione degli Access Point (in verde)Sempre in riferimento allarchitettura Cisco SWAN, il secondo e terzo livellogerarchico sono occupati dai WDS ed AP.I WDS, fisicamente, sono AP settati in una particolare modalità che conferisce loro lostato di Wireless Domain Services. Il principale scopo di tale configurazione è quellodi definire uninfrastruttura di AP.Un certo numero di AP vengono registrati ad un WDS andando così a costituireuninfrastruttura gestita, dal punto di vista dei servizi di rete, dal WDS stesso.Tra i principali vantaggi che tale soluzione offre vi sono: • riduzione del tempo richiesto per le autenticazioni dei client attraverso un processo, quando possibile, locale. In particolare il processo di autenticazione prevede che le credenziali vengano inviate da un AP al WDS cui è registrato. Nel caso di prima autenticazione da parte del client nellinfrastruttura a carico del WDS, questultimo ne verifica lePaolo Vanacore 566/1539 Pagina 14 di 279
    • credenziali attraverso comunicazione con un server RADIUS, ed infine memorizza le stesse in cache. Con tale strategia di caching, le successive fasi di autenticazione del client nellinfrastruttura risultano più veloci non necessitando di interazioni con il server RADIUS; • assegnazione dello stato di WDS definito come processo autonomo allinterno dellinfrastruttura. Gli AP possono eleggere il miglior dispositivo da definire come WDS. Questo meccanismo si basa sulla valutazione di diversi parametri come, ad esempio, il carico di lavoro. È inoltre possibile definire un dispositivo candidato come WDS principale ed uno o più dispositivi candidati come WDS di backup; • Raccolta dei dati di funzionamento in maniera aggregata. Tutti i dati di funzionamento degli apparati possono essere mantenuti e gestiti in maniera centralizzata sul WDS dellinfrastruttura;Il ruolo degli AP, infine, è quello di offrire, agli utenti provvisti di dispositivi mobili,laccesso alla rete WLAN.I modelli di AP della rete sono due: Cisco Aironet 1210 e Cisco Aironet 1240(fig. 2.2.5). Fig. 2.2.5 – Cisco Aironet 1240Paolo Vanacore 566/1539 Pagina 15 di 279
    • Gli AP della serie 1240 supportano la modalità WDS.Le caratteristiche salienti di questi ultimi sono le seguenti: Fino a 108 Mbps e compatibilità con clientStandard 802.11a ed 802.11g 802.11b.Doppio connettore per antenne RP-TNC Antenne da 2,4 a 5 Ghz. Funzionamento come Access Point o comeModalità Bridge. Cisco IDS/IPS. Funzionalità software Cisco per la sicurezza wireless. Rilevamento Spoofing. Autenticazione: WPA, WPA2, Cisco TKIP,WEPSicurezza e protezione a 40b e 128b, autenticazione EAP-FAST, PEAP- GTC, PEAP-MS-CHAP, EAP-TLS, EAP-TTLS, EAP-SIM, Cisco LEAP. Crittografia: AES-CCMP (WPA2), TKIP(WPA), Cisco TKIP, WPA TKIP, WEP a 40b e 128b. Supporto fino a 12 canali non sovrapposti e, potenzialmente, fino a 23 canali.Varie Alimentazione PoE IEEE 802.3af. RAM da 32MB.Memoria 16MB di memoria flash.Consumi 12,95W massimo. Cisco IOS.Software Cisco Unified Wireless Network Software.Paolo Vanacore 566/1539 Pagina 16 di 279
    • 2.3 Dati generali sullinfrastruttura di rete wirelessNella figura a seguire viene mostrato lo stato di avanzamento dei lavori della retewireless di Ateneo. Questi dati sono stati prelevati dal sito www.ict4university.gov.itche riporta lo stato di avanzamento dei progetti di ogni singola Università chepartecipa al progetto. In particolare, di seguito, vengono mostrati i dati relativi alprogetto “WiFi SUD” limitatamente allUniversità Federico II. Fig. 2.3.1 – stato attuale dei lavori in riferimento alliniziativa “WiFi SUD”. Dati prelevati dal sito: www.ict4university.gov.itPaolo Vanacore 566/1539 Pagina 17 di 279
    • I seguenti grafici sono stati realizzati a partire dai dati rilevati dai WLSE in data12/01/2010. È importante notare che tali dati risultano essere delle stime indicativedella reale ed attuale struttura della rete, in quanto la loro produzione non è totalmenteautomatizzata. In particolare la categorizzazione degli AP e linserimento di nuoviapparati, ad esempio, è a carico del personale tecnico-amministrativo. Distribuzione AP per zona Ubicazione Numero AP Centro Storico 218 Monte SantAngelo 307 Policlinico 73 Totale 598 12,21% 36,45% Centro Sto- rico MSA Policlinico 51,34% Tipologia AP Modello AP Quantità Cisco Aironet 1210 321 Cisco Aironet 1240 277 Totale 598 46,32% 53,68% Cisco Aironet 1210 Cisco Aironet 1240Paolo Vanacore 566/1539 Pagina 18 di 279
    • Distribuzione Subnet Ubicazione Numero Subnet Centro Storico 19 Monte SantAngelo 16 Policlinico 2 Totale 37 5,41% Centro Sto- 51,35% 43,24% rico MSA Policlinico Tipologie IP IP Pubblico IP Privato Totali Subnet 13 24 37 Apparati 378 244 622 IP Pubblici 64,86% IP Privati 39,23% IP Privati 60,77% 100 35,14% IP Pubblici 50 0 Subnet ApparatiPaolo Vanacore 566/1539 Pagina 19 di 279
    • Percentuale WDS attivi/di backup Stato Numero WDS WDS Attivi 25 WDS di Backup 24 Totale 49 51,02% 48,98% WDS Attivi WDS Backup Distribuzione WDS Ubicazione Numero WDS Centro Storico 26 Monte SantAngelo 19 Policlinico 4 8,16% 53,06% Centro Storico 38,78% MSA PoliclinicoDai dati rilevati si evince unalta concentrazione di Access Point nella sede di MonteSantAngelo, seguita dal Centro Storico e quindi dal Policlinico. È inoltre interessantenotare come il rapporto dei WDS, effettivamente di 1:1, presenta un WDS attivo in piùrispetto a quelli di backup. Ciò può essere dovuto al malfunzionamento di un WDS dibackup o alla caduta di uno attivo che ha comportato il passaggio di un WDS dallostato di backup allo stato attivo.Paolo Vanacore 566/1539 Pagina 20 di 279
    • 2.3.1 Infrastruttura di Monte SantAngelo Tipologia AP Modello AP Quantità Cisco Aironet 1210 125 Cisco Aironet 1240 182 Totale 307 40,72% Cisco Ai- ronet 1210 59,28% Cisco Ai- ronet 1240 Tipologie IP IP Pubblico IP Privato Totali Subnet 7 9 16 Apparati 195 128 323 IP Pubblici 56,25% IP Privati 39,63% IP Privati 60,37% 100 43,75% IP Pubblici 50 0 Subnet ApparatiPaolo Vanacore 566/1539 Pagina 21 di 279
    • Percentuale WDS attivi/di backup Stato Numero WDS WDS Attivi 9 WDS di Backup 10 Totale 19 47,37% 52,63% WDS Attivi WDS Backup 2.3.2 Infrastruttura del Centro Storico Tipologia AP Modello AP Quantità Cisco Aironet 1210 124 Cisco Aironet 1240 94 Totale 218 43,12% Cisco Aironet 1210 56,88% Cisco Aironet 1240Paolo Vanacore 566/1539 Pagina 22 di 279
    • Tipologie IP IP Pubblico IP Privato Totali Subnet 4 15 19 Apparati 110 116 226 78,95% IP Pubblici 51,33% IP Privati IP Privati 48,67% 100 21,05% IP Pubblici 50 0 Subnet Apparati Percentuale WDS attivi/di backup Stato Numero WDS WDS Attivi 14 WDS di Backup 12 Totale 26 46,15% 53,85% WDS Attivi WDS BackupPaolo Vanacore 566/1539 Pagina 23 di 279
    • 2.3.3 Infrastruttura del Policlinico Tipologia AP Modello AP Quantità Cisco Aironet 1210 72 Cisco Aironet 1240 1 Totale 73 1,37% Cisco Aironet 1210 Cisco Aironet 1240 98,63% Tipologie IP IP Pubblico IP Privato Totali Subnet 2 0 2 Apparati 73 0 73 100 80 100,00% 100,00% IP Pubblici 60 IP Privati 40 20 0 0,00% 0,00% IP Privati IP Pubblici Subnet ApparatiPaolo Vanacore 566/1539 Pagina 24 di 279
    • Percentuale WDS attivi/di backup Stato Numero WDS WDS Attivi 2 WDS di Backup 2 Totale 4 50,00% 50,00% WDS Attivi WDS BackupPaolo Vanacore 566/1539 Pagina 25 di 279
    • 3 Monitoraggio di reteUna corretta valutazione dello stato di un sistema complesso è alla base del processo dimanutenzione, gestione ed evoluzione del sistema stesso. Da questa considerazionenasce la necessità di fornire adeguati strumenti che consentano valutazioni corrette.Il monitoraggio, inteso come strumento di rappresentazione dello stato di un sistema,svolge quindi un ruolo di primaria importanza nella vita ed evoluzione del sistemastesso. Le informazioni che un sistema di monitoraggio deve fornire devono quindirisultare esatte e rilevanti.Al fine di caratterizzare lo stato della rete è opportuno isolarne le principali entità: Entità Esempi di parametri caratterizzanti Utente Numero di utenti connessi. Stato (attivo/non attivo); Up Time; Apparato (WDS/AP) Consumi; Velocità di connessione. Dati di funzionamento dei principali protocolli come: Protocollo il numero e lo stato di connessioni TCP/IP; numero di datagrammi UDP inviati, errati, e così via.Si distinguono inoltre due tipi di monitoraggio: passivo ed attivo.In quello di tipo passivo il sistema di monitoraggio si limita ad aggregare leinformazioni fornitegli dalle entità della rete. Ciò significa che gli apparati devonoessere dotati di sistemi di memorizzazione e devono offrire i servizi necessari perlaccesso ai dati.I monitoraggi attivi, invece, raccolgono informazioni sullo stato della rete attraversoPaolo Vanacore 566/1539 Pagina 26 di 279
    • processi di interazione con la rete stessa. Un monitoraggio attivo è, ad esempio, quellobasato sulla tecnica Packet-pair. Tale tecnica fa uso di code FIFO (coda del tipo FirstIn First Out) al fine di misurare la larghezza di banda di un collegamento.Il sistema di monitoraggio previsto nel progetto cui afferisce il presente lavoro prevedeun monitoraggio di tipo passivo ed è quindi opportuno analizzare in maniera esaustivail protocollo maggiormente utilizzato in tale ambito: il protocollo SNMP. 3.1 Il protocollo SNMP: Simple Network Management ProtocolIn riferimento allo stack ISO/OSI, il protocollo SNMP si colloca al livello 7 (livelloapplicazione, corrispondente al livello 4 dello stack TCP/IP) e, al fine di garantire unbasso overhead sul traffico di rete, fa uso di datagrammi UDP (porte 161 e 162) dellivello di trasporto.Come si evince dallacronimo “Simple Network Management Protocol”, lSNMP nascecon lo scopo di fornire uno strumento di gestione e supervisione di apparati di rete.LSNMP si basa su tre principali tipi di entità: 1. management object – il sistema gestito (porta UDP 161); 2. management agent – lagente di gestione; 3. manager – sistema di gestione (porta UDP 162).Per sistema gestito sintende un qualunque apparato collegato in rete (uno switch, unrouter, una stampante, un server,...) in grado di fornire uninterfaccia di gestioneSNMP. Tale interfaccia viene realizzata per mezzo di almeno un agente di gestionedetto master ed eventuali altri agenti detti subagent. Gli agenti/sotto-agenti sonomoduli software con responsabilità decisionali di gestione limitatamente ad unPaolo Vanacore 566/1539 Pagina 27 di 279
    • particolare sottosistema o relativamente ad un particolare aspetto del sistema overisiedono (management object).In sistemi “semplici” è possibile definire un unico agente di gestione che, in tal caso,svolge sia il ruolo di master che di subagent e, per tale motivo, viene denominatosemplicemente agent.Ogni agent/subagent gestisce una struttura dati denominata MIB (ManagementInformation Base). Tale struttura modellizza lo stato di un sottosistema in base a suoiparametri caratterizzanti che si desidera gestire. È importante constatare che ognimodifica ad un parametro della MIB si ripercuote sullo stato del sistema e ciò permettetutte le funzionalità di gestione del sottosistema. Come precedentemente accennato, lacoerenza della MIB, rispetto allo stato del relativo sistema/sottosistema cherappresenta, e viceversa, è a carico degli agent/subagent.Laccesso alla MIB può essere in lettura e/o in scrittura e rappresenta linterfacciafornita al manager del sistema. In particolare il manager comunica con i sistemi gestititramite i seguenti tipi di messaggi: • richieste SNMP ◦ GET, per la lettura; ◦ GETNEXT, per la lettura iterativa su una sequenza di dati della MIB; ◦ GETBULK, per la lettura di un blocco di dati della MIB; ◦ SET, per la scrittura di uno o più dati della MIB. • notifiche SNMP ◦ TRAP, sono messaggi asincroni inviati dallagent per segnalare eventi (usati, ad esempio, per i sistemi di allarmistica); ◦ INFORM, notifiche con ACK per informazioni di stato generiche.Paolo Vanacore 566/1539 Pagina 28 di 279
    • La MIB ha una struttura di tipo albero n-ario dove ogni sotto-albero è detto modulo ele foglie sono gli oggetti. I moduli vengono definiti in base ad unaggregazione logicadi oggetti.Ogni nodo/foglia dellalbero MIB è identificato univocamente per mezzo di unasuccessione di valori numerici separati da un punto. In particolare ogni elemento(nodo/foglia) è identificabile per mezzo della successione di numeri ottenuta dalcammino che dalla radice conduce ad esso. Il singolo valore numerico di un modulo èassegnato dalla IANA (Internet Assigned Number Authority). La successione di taliidentificativi è detta OID (Object IDentifier). LSNMP definisce, inoltre, una strutturaMIB standard di cui è possibile visionarne una porzione in figura 3.1.1. ISO Root Standard ISO 1 Org Per le organizzazioni che 3 possono emanare standard Dod Per il Dipartimento della 6 difesa americano Per usi futuri OSI Internet 1 Mgmt Experi- Directory Private 2 mental 1 4 3 MIB-II MIB definite Enterpises 1 Ufficialmente 1 DallInternet Architecture Board Per esperimenti Moduli non standard Internet definiti dai costruttori Fig. 3.1.1 – porzione dellalbero MIB standardPaolo Vanacore 566/1539 Pagina 29 di 279
    • Per quanto riguarda i tipi di dati, che il protocollo SNMP defisce, essi si distinguonoin: primitivi e non primitivi.I tipi primitivi sono: • Integer – per i valori interi positivi o negativi incluso lo zero; • Octet String – per gli insiemi ordinati di byte; • Object Identifier – per i valori unici secondo le specifiche ASN.1; • NULL – per il tipo nullo.I tipi non primitivi previsti dalllo standard sono: • Indirizzi di rete – per la rappresentazione degli indirizzi IP; • Counter – per i valori interi non negativi che possono essere unicamente incrementati fino ad un valore massimo, raggiunto il quale vengono azzerati; • Gauge – per gli interi non negativi che possono essere sia incrementati che decrementati; • Time Tick – per la rappresentazione di intervalli di tempo nella gestione degli eventi; • Opaque – tale tipo è in grado di mantenere qualunque valore e viene usato per le informazioni per le quali non sono strettamente applicabili i tipi precedentemente descritti.A partire dalla versione 2 dellSNMP, per offrire un minimo livello di sicurezzatotalmente assente nella versione 1, è stato introdotto il concetto di comunità.LSNMPv2 definisce una comunità come un insieme di sistemi facenti parte di una reteSNMP. Ogni comunità viene identificata per mezzo di una stringa di 32Byte e ciascunsistema può appartenere ad una o più comunità. Gli agent accettano quindi richiestesolo da manager della stessa comunità cui possono essere assegnati tre tipi diPaolo Vanacore 566/1539 Pagina 30 di 279
    • autorizzazioni: • read – autorizzazione in lettura. Il manager può unicamente richiedere allagent il valore degli oggetti della MIB (messaggi GET); • write – autorizzazione in scrittura. Il manager può richiedere allagent la lettura e la scrittura di valori degli oggetti della MIB (messaggi GET e SET); • trap – autorizzazione per le notifiche. Il manager può richiedere allagent di ricevere notifiche relative agli oggetti della MIB (messaggi TRAP/INFORM);È utile ricordare che lultima versione dellSNMP, definita nel documento RFC2570, èla 3. Questa versione risolve diversi problemi che vanno dalla sicurezza allastandardizzazione delle varie implementazioni delle versioni precedenti. Tale versioneunifica il concetto di agent e manager in ununica entità detta SNMP entity. È inoltrestata adottata unarchitettura modulare e diversi algoritmi di autenticazione, sicurezza ecrittografia.Per concludere questa trattazione del protocollo SNMP è opportuno menzionare alcunidei software Open Source maggiormente diffusi: • Net-SNMP; • OpenSNMP – software multi-thread per SNMPv3; • SNMP4J – libreria per Java; • Netsnmpj – libreria per Java.Paolo Vanacore 566/1539 Pagina 31 di 279
    • 3.2 CactiIl software utilizzato per la raccolta dei dati di esercizio degli apparati della retewireless di Ateneo è lapplicazione open source Cacti (fig. 3.2.1).La scelta di utilizzare Cacti come strumento di raccolta dati è dettata principalmentedalle sue caratteristiche, di seguito analizzate, che rientrano in maniera più cheadeguata nel contesto in esame. Fig. 3.2.1 – schermata di esempio di Cacti. In particolare è possibile notare il grafico relativo al numero di processi attivi sulla macchina che ospita il sistema di monitoraggio.Per completezza di informazione si menziona anche unalternativa, lapplicativoPaolo Vanacore 566/1539 Pagina 32 di 279
    • Nagios. Sono molti gli aspetti in comune con Cacti e, proprio per questo, è importantenotare che lapplicazione realizzata, descritta nei successivi paragrafi, è facilmenteadattabile/estendibile alluso di Nagios. Una differenza evidente tra i due softwarerisiede nel fatto che Nagios è utilizzato maggiormente per la realizzazione di sistemi diallarmistica, più che per monitoraggio puro.Tornando a Cacti, questi integra una serie di tool, sempre open source, al fine difornire un sistema semplice e completo per il monitoraggio passivo di retiinformatiche.Più dettagliatamente Cacti si basa sui seguenti strumenti: • Net-SNMP, per le interrogazioni SNMP; • RRDTool, per la persistenza dei dati frutto di monitoraggio e la loro presentazione per mezzo di grafici; • piattaforma LAMP (Linux Apache Mysql Php), ed in particolare: ◦ PHP ed Apache, per la presentazione dei dati e per le interfacce utente; ◦ MySQL, per la persistenza dei dati di configurazione.Una schematizzazione modulare, esplicativa, può essere la seguente: Net­SNMP CACTI Piattaforma LAMP RRDTool MySQL DB Fig. 3.2.2 – struttura modulare di CactiPaolo Vanacore 566/1539 Pagina 33 di 279
    • Unimportante caratteristica di Cacti, che gli conferisce ampi margini di espansibilità, èlarchitettura a plug-in.Tra i plug-in più rilevanti vi sono: • Discovery – auto rilevamento di dispositivi di una subnet non monitorati da Cacti; • Host Info – consente di visualizzare informazioni sugli host; • Monitor – mostra gli stati degli host monitorati generando segnali acustici in caso di “cadute”; • Uptime – consente di conoscere gli uptime dei dispositivi monitorati; • Weathermap – consente di definire mappe delle reti arricchite con i dati di monitoraggio; • NPC – plugin per integrare il sistema di monitoraggio Nagios allinterno di Cacti.Per quanto riguarda la definizione dei monitoraggi, le chiamate a Net-SNMP possonoessere definite per mezzo di: • script di shell bash; • script Perl; • definizione di template in XML (eXtensible Markup Language).Una volta definite le interrogazioni SNMP desiderate, attraverso processo di polling,Cacti prevede ad eseguirle ad intervalli di tempo regolari, passandone i risultati adRRDTool. In prima istanza, RRDTool può essere considerato come un vero e propriodatabase ottimizzato per gli ambienti di monitoraggio in genere. Nel successivoparagrafo sarà descritto in maniera esaustiva tale software, del quale Cacti vieneconsiderato uninterfaccia user friendly, in quanto lapplicazione realizzata prevede, aPaolo Vanacore 566/1539 Pagina 34 di 279
    • livello del data layer, una ricca interazione con questultimo.Al fine di descrivere in maniera più chiara i processi legati alla raccolta dati di Cacti,se ne riporta uno schema esplicativo contestualizzato alla rete wireless di ateneo: MSA Centro Storico AP1 APa AP1 APb AP1 APc AP1 APd Policlinico WDSx WDS1 WDS1 WDSy AP1 SN WDS1 SN M SNMP SN MP M APe   P MP SN P AP1 WDSz SN MP Net­SNMP APf CACTI      RRD Files Piattaforma LAMP RRDTool MySQL DB Fig. 3.2.2 – processo di raccolta e persistenza dati di Cacti nellambito della rete wireless di ateneoDallo schema sopra riportato è possibile osservare come Cacti, attraverso luso di Net-SNMP, è in grado di raccogliere dati dalle tre sedi principali della rete wireless diateneo. È importante notare che le interrogazioni SNMP vengono effettuateunicamente sui WDS in quanto, questi ultimi, come descritto nel paragrafo 2.2,mantengono le informazioni di tutti gli apparati dellinfrastruttura a loro carico.Ad ogni interrogazione i dati vengono quindi passati ad RRDTool che procede allastoricizzazione degli stessi.Paolo Vanacore 566/1539 Pagina 35 di 279
    • 3.3 RRDTool: Round-Robin Database ToolRRDTool (acronimo di Round Robin Database Tool) è un software open sourcerealizzato interamente in C da Tobias Oetiker ed è uno degli strumenti maggiormenteutilizzati nellambito dei sistemi di monitoraggio in genere. Il compito principale diRRDTool, in un sistema di monitoraggio, è larchiviazione di serie temporali.Le principali caratteristiche (fig. 3.3.1) sono: • dimensioni degli archivi (file RRD – Round Robin Database), a regime, costanti; • dump degli archivi in file XML; • fetch di serie temporali parziali dagli archivi; • rappresentazione dei dati per mezzo di grafici (fig. 3.3.2).      RRD Files RRDTool STDOUT ASCII XML files dump file dump file Stream Stream Fig. 3.3.1 – caratteristiche principali di RRDToolPaolo Vanacore 566/1539 Pagina 36 di 279
    • Fig. 3.3.2 – esempio di grafico generato da RRDToolAl fine di analizzare, in maniera dettagliata, gli RRD si riporta un diagramma di classe UMLche ne sintetizza la struttura logica: Fig. 3.3.3 – rappresentazione della struttura logica degli RRD per mezzo di diagramma di classe UMLPaolo Vanacore 566/1539 Pagina 37 di 279
    • Passando in rassegna ogni singola classe del diagramma precedente, è possibile notareche ogni RRD è caratterizzato da: • version – una stringa indicante il numero di versione dellRRD (attualmente la 003); • step – un valore numerico intero che indica la frequenza, in secondi, con cui lRRD viene aggiornato; • lastupdate – intero che rappresenta la data di ultimo aggiornamento dellRRD, in numero di secondi trascorsi dal 01/01/1970 00:00:00 (Unix Epoch – dora in avanti a tale formato ci si riferirà anche con il nome di TimeStamp).Ad ogni RRD sono associati uno o più RRA (Round Robin Archive) ed uno o più DS(Data Source).Un DataSource rappresenta una fonte di dati (ad esempio “il carico del processore diun server”, “il numero di pacchetti inviati da uno switch”,...) allinterno di un RRD.Ogni DS ha i seguenti attributi: • name – stringa contenente il nome del DataSource. Tale valore identifica il DS in maniera univoca allinterno dellRRD; • heartbeat – letteralmente “battito del cuore/cardiaco”. Tale intero indica il numero massimo di secondi che possono trascorrere tra linserimento di due dati consecutivi relativi al DS stesso. Se allo scadere dellheartbeat non viene inserito un nuovo dato relativo al DataSource, RRDTool provvede a memorizzare un valore “speciale” di tipo UNKNOWN (sconosciuto). • min, max – interi rappresentanti gli estremi dellintervallo [min, max] cui devono appartenere i dati relativi al DataSource. Attraverso tali valori è quindi possibile definire il dominio di validità per i dati del DataSource.È utile tener presente che nella letteratura di RRDTool viene utilizzato il nome “PDP”(Primary Data Point) per indicare i dati che vengono inseriti negli RRD prima che siaPaolo Vanacore 566/1539 Pagina 38 di 279
    • avviato il processo di memorizzazione.Ogni DS può essere definito di uno dei seguenti quattro tipi: • COUNTER – tipo di contatore che può essere unicamente incrementato fin quando non va in overflow (32 o 64bit in base allarchitettura). Un esempio che può prevedere un DS di questo tipo può essere il numero totale di autenticazioni su un server RADIUS; • DERIVE – tipo di dato senza controllo sulloverflow dove il nuovo dato viene memorizzato come la differenza con il precedente diviso lintervallo di tempo trascorso tra le due misurazioni. Inoltre al fine della persistenza del nuovo dato, tale differenza devessere positiva. RRDTool, quindi, allinserimento di un valore per un DS del tipo DERIVE, effettua la differenza tra il nuovo valore e quello precedentemente memorizzato dividendo tale risultato per il tempo trascorso. Indicato con xi il valore di una misurazione al tempo ti e con yi il valore del nuovo dato da memorizzare, la formula, applicata da RRDTool, può essere così indicata: { x n− x n−1 y i= t n−t n−1 ⇔ x n x n−1 y i −1 ⇔ x n≤x n−1 Un esempio può essere il tasso di utenti che si connettono ad una rete. • GAUGE – i DS di questo tipo sono impiegati per usi generici, per misurazioni, quindi, di natura variabile. Un DS GAUGE, può riferirsi, ad esempio, alla temperatura di una CPU; • ABSOLUTE – tipo utilizzato per tutti i contatori che tendono velocemente verso loverflow. Luso tipico si basa su letture ed azzeramenti successivi del contatore.Un altro tipo di DS, non trattato approfonditamente in questo contesto in quanto diPaolo Vanacore 566/1539 Pagina 39 di 279
    • raro utilizzo e comunque non usato nel sistema di monitoraggio, è il COMPUTE. Taletipo consente di definire un DS in funzione di altri dello stesso RRD.Come precedentemente accennato, ogni RRD contiene uno o più RRA (Round RobinArchive). Tali oggetti sono gli archivi che si occupano di conservare tutte le seriestoriche dei DS dellRRD. Ad ogni archivio è associata una o più funzioni diconsolidamento CF (Consilidation Function) il cui scopo è consolidare i dati (PDP)dei DS prima di memorizzarli. In particolare tale funzione viene applicata per ogni DSdellRRD su un certo numero di PDP.Le possibili funzioni di consolidamento sono le seguenti: • AVERAGE – media tra un certo numero di PDP; • MIN – valore minimo tra una serie di PDP; • MAX – valore massimo tra una serie di PDP; • LAST – ultimo valore di una serie di PDP.Ogni CF ha i seguenti attributi: • xff – XFileFactor. Tale valore, reale appartenente allintervallo [0,1] e di default pari a 0, indica la massima frequenza dei dati che possono essere di tipo UNKNOWN al fine di poter applicare la CF. Questo valore è tipicamente pari a 0.5 ed indica, quindi, che al più il 50% dei dati possono essere di tipo UNKNOWN. Luso di tale attributo è significativo nei monitoraggi in ambienti particolarmente “rumorosi”, dove, cioè, le misurazioni possono risultare disturbate; • pdp_per_row – indica ogni quanti PDP devessere applicata la funzione di consolidamento; • rows – massimo numero di dati che lRRA può archiviare.Per quanto concerne il Database, presente in ogni RRA, esso è costituito dai risultatiPaolo Vanacore 566/1539 Pagina 40 di 279
    • delle CF. A regime, il numero di righe, è costante e pari al parametro rows della CF.Nello schema a seguire viene mostrato il flusso dei dati (in rosso) durante il processodi memorizzazione allinterno di un RRD. È da notare che sono presenti più DS e piùRRA.  RRD 1 DS 2 RRA CF 3 Database Fig.3.3.4 – Flusso dei dati durante il processo di memorizzazione allinterno di un RRD. Tale processo è formato dalle seguenti fasi: 1) inserimento dati (PDP); 2) Consolidamento dati (CF); 3) Archiviazione dati (Database).Dallo schema si evince come, quando viene inserito un numero di dati (PDP) pariallattributo pdp_per_row di una CF, viene eseguito il consolidamento degli stessi ed ilrisultato inserito nel Database. In particolare vengono eseguite tutte le CF per le qualisi è raggiunto il valore pdp_per_row.Per quanto riguarda lalgoritmo Round Robin, dal quale il tool prende il nome, è allabase della logica di funzionamento dei Database contenuti negli RRD. Tali Database,infatti, possono essere definiti come strutture dati del tipo “code circolari” adimensioni fisse. In particolare, raggiunta la lunghezza massima della coda, ognisuccessivo elemento viene accodato dopo aver eliminato la testa della coda.Nel successivo schema è possibile notare, con maggior precisione, qual è la strutturainterna dei Database:Paolo Vanacore 566/1539 Pagina 41 di 279
    • #DS values values Database Rows elementi Fig. 3.3.5 – struttura dei Database (code circolari a lunghezza fissa) degli RRAIl Database ha quindi una dimensione massima pari al parametro rows della CF.Ogni suo elemento, inoltre, è un vettore di lunghezza pari al numero dei DS presentinellRRD tale che, li-esimo elemento si riferisce alli-esimo DS. Lassociazione tra iDS ed i dati è quindi basata sullordine in cui i DS sono stati definiti nellRRD.Linformazione che ogni dato conserva è il valore del risultato di una CF applicata aduna serie di PDP (reale in forma normalizzata), associato al relativo TimeStamp.Ricordando il significato dei seguenti parametri • RRD.step : frequenza di aggiornamento RRD in secondi • CF.pdp_per_rows : frequenza di aggiornamento Database in funzione dello step • CF.rows : massimo numero di record del Databasesi ricava che ogni Database • ha una risoluzione pari alla frequenza daggiornamento del Database stesso:  T x =  T D = pdp_per_row ⋅ step sec i i=0,... , rows−1 • conserva uno storico di:  T S = rows ⋅ pdp_per_row ⋅ step sec = rows ⋅ T DPer completare la trattazione di RRDTool si riporta un esempio di utilizzo chePaolo Vanacore 566/1539 Pagina 42 di 279
    • consente di ottenere un semplice monitoraggio della temperatura di una CPU dual coresu un sistema Linux. • Creazione del file RRD con le seguenti caratteristiche: ◦ coretemp.rrd – nome del file; ◦ step 15 – frequenza aggiornamento dellrrd pari a 15 secondi; ◦ un DS per core: 1. core_01 di tipo GAUGE con heartbeat pari a 30 secondi e dominio pari allintervallo [0, 150]; 2. core_02 di tipo GAUGE con heartbeat pari a 30 secondi e dominio pari allintervallo [0, 150]; ▪ Considerazioni sui DS: tali datasources consentono di memorizzare valori numerici/temperature che vanno da 0 a 150 (in questo esempio °C). Ogni datasource devessere aggiornato con frequenza pari a 30 secondi. ◦ tre RRA tutti con funzioni di consolidamento di tipo AVERAGE (consolidamento per mezzo della media dei PDP) ed XFileFactor pari a 0.5 (massimo il 50% dei PDP possono essere UNKNOWN). Per quanto riguarda i valori di pdp_per_row (numero di PDP a cui viene applicata la funzione di consolidamento) e massimo numero di righe dei Database vengono usati, nellordine, i seguenti valori: 1. pdp_per_row pari a 1 e 9600 rows (valori memorizzabili); 2. pdp_per_row pari a 4 e 9600 rows; 3. pdp_per_row pari a 24 e 9600 rows; ▪ Considerazioni sugli RRA: i Database degli RRA hanno, nellordine, risoluzioni e mantengono storici pari a:Paolo Vanacore 566/1539 Pagina 43 di 279
    • 1. risoluzione:  T D =pdp_per_row⋅step=1⋅15 sec=15 sec 1 dimensione storico:  T S =rows⋅T D =9600⋅15sec=144000sec=40h 2. risoluzione:  T D =pdp_per_row⋅step=4⋅15 sec=60 sec=1min 1 dimensione storico:  T S =rows⋅T D =9600⋅60sec=576000sec=160h 3. risoluzione:  T D =pdp_per_row⋅step=24⋅15 sec=360 sec=6min 1 dimensione storico:  T S =rows⋅T D =9600⋅360sec=3456000sec=960h=40gg ◦ Comando di shell bash per la creazione del file rrd: rrdtool create coretemp.rrd --step 15 DS:core_0:GAUGE:30:0:150 DS:core_1:GAUGE:30:0:150 RRA:AVERAGE:0.5:1:9600 RRA:AVERAGE:0.5:4:9600 RRA:AVERAGE:0.5:24:6000 • Creazione di uno script bash per popolare il file rrd: #!/bin/bash while [ 1 ] ; do #lettura temperatura dei core CORE0_TEMP=`sensors | grep "Core 0:" | cut -f 8 -d | sed "s/°C$//"` CORE1_TEMP=`sensors | grep "Core 1:" | cut -f 8 -d | sed "s/°C$//"` #memorizzazione dei valori nel file rrd rrdtool update coretemp.rrd N:$CORE0_TEMP:$CORE1_TEMP #attesa 15 secondi prima del successivo rilievo sleep 15s donePaolo Vanacore 566/1539 Pagina 44 di 279
    • • Risultati: una volta creato lrrd ed avviato lo script bash, che necessita del pacchetto sensors installato sulla macchina, dopo unattesa necessaria a popolare lrrd, è possibile eseguire il seguente comando al fine di ottenere un grafico rappresentativo dei due DS: rrdtool graph coretemp.png DEF:core_0=coretemp.rrd:core_0:AVERAGE DEF:core_1=coretemp.rrd:core_1:AVERAGE LINE1:core_0#0000ff:Core0_Temp LINE1:core_1#ff0000:Core1_Temp --start -30m Tale comando consente di ottenenre il seguente grafico relativo allultima mezzora di rilevamenti: Fig. 3.3.6 – esempio di grafico generato con RRDTool relativo alle temperature di due core di una CPU nellultima mezzora Essendo numerose le opzioni di personalizzazione per i grafici di RRDTool, si rimanda alla relativa documentazione ufficiale per ulteriori approfondimenti.Paolo Vanacore 566/1539 Pagina 45 di 279
    • 4 Lapplicazione realizzata 4.1 RequisitiLapplicazione realizzata risponde ai seguenti, principali requisiti: 1. integrazione con il sistema di monitoraggio; 2. strumenti per la valutazione di statistiche di esercizio della rete wireless di ateneo;Lattuale sistema di monitoraggio consta di un server sul quale è installato il softwareCacti opportunamente configurato per la raccolta passiva dei dati dalla rete.I dati di rete attualmente monitorati sono: • Numero di AP attivi; • Numero di utenti connessi; • Dati sui protocolli: ◦ SNMP; ◦ IP; ◦ TCP; ◦ UDP.Le interrogazioni SNMP vengono effettuate sui WDS della rete per ogni principalesede di ateneo: • Monte SantAngelo ed Ingegneria; • Centro Storico; • Policlinico.Paolo Vanacore 566/1539 Pagina 46 di 279
    • Al fine di ottenere unalta portabilità ed evolvibilità, si è deciso di realizzareunapplicazione interamente in Java.Lo schema a seguire mostra linterazione tra il sistema di monitoraggio e lapplicazionerealizzata: WiFi Unina   Applicazione  Cacti Java Fig. 4.2.1 – contestualizzazione dellapplicazione JAVA realizzata rispetto al sistema di monitoraggioIl primo, principale requisito, inerente lintegrazione, implica la necessità di accesso aidati di Cacti. In tal senso questi risulta particolarmente “chiuso”, non prevedendointerfacce per linterazione verso lesterno.Come precedentemente descritto, il datalayer di Cacti si basa sulluso di: • MySQL per i dati di configurazione; • RRDTool per la memorizzazione dei dati frutto di monitoraggio.Per quanto riguarda il database MySQL, per mezzo di un processo di reverseengineering, tramite luso dello strumento software open source SQLFairy, è statoricavato il seguente diagramma ER:Paolo Vanacore 566/1539 Pagina 47 di 279
    • Fig. 4.2.2 – diagramma ER del database di Cacti ottenuto con SQLFairyPaolo Vanacore 566/1539 Pagina 48 di 279
    • Essendo, ovviamente, il diagramma ER normalizzato, è stato necessario comprendereil significato delle tabelle osservandone il contenuto durante il funzionamento.A seguito di tale processo sono state individuate le seguenti tabelle dinteresse: • host – per conoscere gli host monitorati da Cacti e le relative informazioni; • poller_item – per conoscere, per ogni host, i dettagli delle interrogazioni effettuate. Tra le informazioni presenti vi sono: ◦ informazioni sul protocollo SNMP usato (versione, community name, eventuale password per la versione 3, porta, timeout per le richieste,...); ◦ informazioni circa RRDTool ed, in particolare, il pathname dellrrd dove vengono salvati i risultati dellinterrogazioni.Le due tabelle sono in relazione uno a molti e quindi, per ogni host possono esserci piùpoller_item.Laccesso ai dati degli rrd è basato, invece, sulluso dei file XML di dump.Tutti i dettagli circa laccesso ai dati vengono trattati nei successivi paragrafi. 4.2 Architettura generaleLarchitettura dellapplicazione realizzata può essere classificata come: Client/Servermulti-tier.Laccesso ai dati di monitoraggio è realizzato attraverso due componenti: • Data Server; • Data Client.Il Data Server, residente sul server di monitoraggio (dove è installato Cacti), offre duetipologie di servizi:Paolo Vanacore 566/1539 Pagina 49 di 279
    • • accesso ai dati del database di Cacti; • accesso agli rrd.Il Data Client è costituito da alcuni componenti per gestire la persistenza dei datidellapplicazione realizzata, attraverso interazione con uno o più Data Server.Al fine di offrire servizi di amministrazione del Data Client, questultimo è stato dotatodi un componente detto Admin Server.Per la presentazione dei dati e interfacce utente si è fatto uso di Servlet Java, pagineJSP e Java Beans, come spiegato nei successivi paragrafi.Uno schema che sintetizza larchitettura dellapplicazione è il seguente: GUI Servlet/JSP/Beans socket Amministrazione Admin Server Thread-safe Collections Data Client Accesso ai dati di monitoraggio socket Data ServerAd inizio paragrafo, larchitettura è stata definita come Client/Server multi-tier inquanto i componenti comunicano per mezzo di una logica Client/Server. Lunicaeccezione è linterazione tra lAdmin Server ed il Data Client che, attraverso CollezioniJava thread-safe, condividono le principali entità dellapplicazione.Paolo Vanacore 566/1539 Pagina 50 di 279
    • 4.3 Accesso ai dati di monitoraggioCome precedentemente accennato il Data Server risiede sulla stessa macchina dovèinstallato Cacti. Questo vincolo deriva dal fatto che il dump degli rrd in files XML èpossibile unicamente sulla stessa architettura dove sono stati creati.Il seguente schema riporta i processi di interazione tra i principali componentidesignati per laccesso ai dati di monitoraggio: WiFi Unina         SNMP   RRD Files Cacti Cacti DB     XML XML Dump Dump Files Files JDBC Dumper Parser SAX         Socket        Socket XML files,         DATA SERVER MySQL DB info DATA CLIENT Parser JDBC   Dom/XPath XML Config RRDB Files Fig. 4.3.1 – architettura modulare per laccesso ai dati di monitoraggioTale soluzione consente di avere: • uno o più server di monitoraggio; • gestione centralizzata dei dati dinteresse.Paolo Vanacore 566/1539 Pagina 51 di 279
    • 4.3.1 Server di monitoraggio: Il Data ServerIl Data Server è un server multithread, che risiedere su una macchina in cui è installatoCacti, che offre i seguenti servizi: • accesso ai dati del database di Cacti ed, in particolare, consente di conoscere: ◦ lista host (con specifica di hostname e descrizione) monitorati da Cacti; ◦ lista dei file rrd (pathname) associati ad un determinato host monitorato. Il servizio richiede la specifica di: hostname/ip dellhost. • accesso ai dati di uno specifico rrd ed, in particolare: ◦ invio di file XML ottenuti da dump di uno specifico rrd. Il servizio richiede la specifica di: pathname del file rrd. ◦ lettura di serie temporali parziali (sotto forma di (valore, data)) relative ad uno specifico DS, di un determinato RRA, contenuti in un file rrd. Tale servizio richiede la specifica di: ▪ pathname rrd; ▪ identificativo rra (nome della funzione di consolidamento); ▪ nome, univoco, del datasource; ▪ risoluzione dei dati ; ▪ tempo (Unix Epoch) a partire dal quale vengono estratti i dati.Per quanto riguarda laccesso al database MySQL di Cacti, viene utilizzato ilconnettore JDBC (Java Database Connectivity), mentre il dump dei file rrd vieneeseguito per mezzo di processi RRDTool.Il Data Server è inoltre configurabile tramite file XML per il quale viene utilizzato ilparser DOM (Document Object Model) ed istruzioni XPath (Xml Path language).Paolo Vanacore 566/1539 Pagina 52 di 279
    • Si riporta di seguito un contenuto desempio di un file di configurazione XML:<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE configuration SYSTEM "server_config.dtd"><!-- Configuration file for DataServer --><configuration> <!-- Listening port --> <serverPort>61000</serverPort> <!-- Pathname to RRDTool binary file --> <rrdtoolPath>/usr/bin/rrdtool</rrdtoolPath> <!-- Parametri per laccesso al db di cacti --> <cactiDb> <!-- Cacti db name --> <dbName>cacti</dbName> <!-- User name for cacti db --> <userName>user_name</userName> <!-- User Password for Cacti db --> <userPwd>user_password</userPwd> </cactiDb></configuration>Come si evince dal codice sopra riportato, è possibile impostare i seguenti parametri diconfigurazione: • numero porta della socket; • pathname al binario di RRDTool; • nome del database di Cacti; • nome utente per laccesso al database di Cacti; • password dellutente per laccesso al database di Cacti.Tutti i files XML utilizzati nellapplicazione vengono validati per mezzo di file DTD(Document Type Definition). Nel caso dei file XML ottenuti dal dump degli rrd, vieneutilizzato il DTD standard di RRDTool reperibile al seguente indirizzo:http://oss.oetiker.ch/rrdtool/rrdtool.dtd.Il processo di validazione viene eseguito sia per verificare che lXML rispetti unastruttura nota, sia, nel caso dei file di configurazione, per poter eseguire istruzioniXPath.Paolo Vanacore 566/1539 Pagina 53 di 279
    • Tutte le richieste e gran parte delle risposte vengono effettuate per mezzo di oggettiserializzati Java su Socket. Nel caso delle risposte vengono utilizzati anche stream dibyte per il trasferimento degli XML. 4.3.2 Il Data ClientPer quanto concerne il Data Client, gli aspetti di maggior rilevanza sono: • il parsing degli XML tramite SAX (Simple Api for Xml); • il database MySQL, denominato RRDB (Round Robin DataBase), per la persistenza dei dati; 4.3.2.1 Parsing di XML dump fileÈ stato scelto di utilizzare il parser SAX per i file di dump in quanto, questi ultimi,rispecchiano lintero contenuto dei file rrd contenendo, quindi, una grossa mole di dati(tutti gli rra per tutti i ds dellrrd).A differenza del parser DOM, che costruisce in memoria lintero albero del file XML,il parser SAX si basa sul paradigma ad eventi e design pattern OBSERVER. Peruna descrizione del pattern Observer si rimanda al paragrafo 4.5.2. In particolare, iprincipali eventi che, durante il parsing, vengono generati da SAX, sono i seguenti: • start element – evento generato alloccorrenza di un tag aperto; • characters – evento generato alloccorrenza di un valore compreso tra un tag di apertura ed uno di chiusura; • end element – evento generato alloccorrenza di un tag di chiusura.È stata quindi realizzata una classe, denominata “RRDAutomata” (fig. 4.3.2.1), cheviene registrata come listener del parser SAX.Paolo Vanacore 566/1539 Pagina 54 di 279
    • Fig. 4.3.2.1.1 – classe RRDAutomata per la rappresentazione in memoria degli rrdTale classe modellizza, nella logica, un automa a pila. Al fine di comprenderne ilfunzionamento si riporta un diagramma degli stati UML: Fig. 4.3.2.1.2 – statechart dellautoma a pila per il parsing degli XML ottenuti dal dump degli rrdPaolo Vanacore 566/1539 Pagina 55 di 279
    • Grazie alluso di uno stack di Object, la classe RRDAutomata, guidata dagli eventigenerati dal parser SAX, è in grado di ricostruire in memoria lesatta struttura dellrrdnel rispetto del seguente diagramma di classe: Fig. 4.3.2.1.3 – diagramma di classe UML per la rappresentazione in memoria degli rrd 4.3.2.2 Il database RRDBIn riferimento alla struttura dei files rrd, è opportuno, in tale contesto, tener presente iseguenti punti: • ogni rrd contiene uno o più archivi rra atti a tener traccia, per mezzo di un database round robin, dei dati monitorati riferiti ad un device; • per ogni rrd è definito un valore, in secondi, chiamato “step”. Tale valore definisce la frequenza di aggiornamento dellrrd; • per ogni rrd è definita una variabile, “lastupdate”, che indica la data dellultimo aggiornamento (nel formato Unix-epoch);Paolo Vanacore 566/1539 Pagina 56 di 279
    • • per ogni rra è definito un valore intero, chiamato “pdp_per_row”, che indica quanti aggiornamenti (letture del dato monitorato) concorrono allinserimento di un dato allinterno di un rra (per mezzo di una funzione di consolidamento); • altro dato importante in questo contesto è la costante “rows” definita per ogni rra. Tale valore indica il numero di righe del database mantenuto dallrra in esame.Ogni database round robin è quindi identificabile per mezzo della coppia:(nome_rrd, id_rra)Per questioni logiche e di miglior comprensione, essendo definita ununica funzione diconsolidamento (CF) per rra, ogni database viene identificato dalla coppia:(nome_rrd, id_cf).Per quanto riguarda il database realizzato per lapplicazione, denominato rrdb, la sceltadel DBMS è stata dettata sia dal tipo di licenza (GNU GPL), sotto la quale è distribuitoMySQL, sia perché esso è già in uso per il software di monitoraggio Cacti.Una problematica di rilievo che è stata affrontata riguarda la replicabilità della logicadi memorizzazione dei database Round Robin in un database di tipo relazionale.Di seguito vengono riportati i dettagli ritenuti di maggior rilievo.Nellimmagine a seguire si riporta una porzione del diagramma EER interessato da taleaspetto:Paolo Vanacore 566/1539 Pagina 57 di 279
    • Fig. 4.3.2.2.1 – porzione del diagramma EER relativo al database “rrdb” realizzato per lapplicazioneCome è stato descritto nei precedenti documenti, la logica di memorizzazione dei datiallinterno dei files di RRDTool, e più in generale di database Round Robin, è basatasu una struttura dati del tipo “vettore circolare”.E possibile adottare diverse tecniche per replicare il comportamento di un vettorecircolare in una base di dati relazionale. Una possibile soluzione, forse la più intuitivae performante, è quella di utilizzare un trigger con le seguenti caratteristiche: • Evento: inserimento di un nuovo record (nella tabella DATA del diagramma EER); • Condizione: la tabella (DATA) ha raggiunto il massimo numero di record memorizzabili (attributo “Rows” della tabella RRA); • Azione: cancellazione del record con data (attributo “Data_Time” della tabellaPaolo Vanacore 566/1539 Pagina 58 di 279
    • DATA) più vecchia.Purtroppo tale soluzione non è direttamente adottabile in MySQL (con lattuale vers.5.1.44 viene segnalato lerrore “1442”) in quanto non è possibile definire trigger in cuievento ed azione sono definiti su una stessa tabella (la tabella target deve differire dallatabella sorgente). Ovviamente per “azioni” sintende qualunque transizione che operisu record diversi da “NEW” ed “OLD”. Questa scelta progettuale ha il fine diprevenire possibili “cicli infiniti” che potrebbero scaturire da eventuali errori nelladefinizione di trigger di questo tipo. Evidentemente tale limitazione non è aggirabileattraverso luso di trigger annidati e/o viste modificabili.È da notare anche il mancato supporto di trigger con eventi del tipo “INSTEAD OF”,classici Oracle, che, con luso combinato di una tabella dappoggio, avrebbe risolto ilproblema.Una strategia alternativa potrebbe essere quella di spostare la responsabilità dieliminare il record “più vecchio”, sul client. In tal caso è opportuno rifiutareinserimenti di nuovi record qualora sia stato raggiunto il numero massimo. Rifiutarequeries di inserimento si traduce nella creazione di un trigger con le stessecaratteristiche di quello precedentemente definito, tranne che per lazione. In tal caso,infatti, lazione deve prevedere il lancio di uneccezione in caso di saturazione delnumero di record.Anche in questo caso la soluzione è stata scartata in quanto non vi è possibilità digenerare eccezioni in MySQL (è solo possibile catturarne).Tralasciando facili critiche si evidenzia la presenza, sul sito di MySQL (sez. bug), didiverse segnalazioni a tal proposito e, in riferimento alle azioni del tipo “INSTEADOF” ed alle eccezioni, è stato appurato che saranno features probabilmenteimplementate nelle prossime versioni.In attesa di nuovi rilasci è stata adottata una soluzione che, anche se funzionante, siauspica sia temporanea.Paolo Vanacore 566/1539 Pagina 59 di 279
    • La soluzione adottata prevede la definizione di una Stored Procedure (“insertData”)per linserimento di record nella tabella DATA. Tale procedura ha la responsabilità diinserire record nella tabella DATA e di verificare e mantenerne costante il numero direcord. Il client della base di dati, quindi, invece di utilizzare loperazione “INSERT”,per tale tabella, deve far uso di tale procedura.In caso di uso di “INSERT”, ed in condizione di tabella “piena”, si è ricorso ad un“trucco” di uso comune. In particolare, non potendo definire e lanciare eccezioni,viene richiamata una procedura inesistente. A seguito di tale chiamata, MySQL generauneccezione che informa dellinesistenza della procedura. Nonostante tale soluzionesia poco elegante e definibile “programmazione sporca”, essa consente di esulare ilclient da responsabilità che riguardano la logica interna della base di dati. Inoltre,tenuto conto della procedura realizzata che il client deve utilizzare, si ritiene che ilrisultato complessivo sia soddisfacente.Per completezza si segnala che, al fine di generare eccezioni in MySQL, un altro“trucco” di uso comune è quello di violare qualche vincolo di integrità. 4.4 Logica di controllo per la gestione dei datiGli aspetti riguardanti la logica di controllo ritenuti di maggior rilievo sono: • amministrazione dei dati; • temporizzazione delle letture degli rrd; • i Monitor ed i Report Statistici.Il componente designato allamministrazione è lAdmin Server. Tale componenteinteragisce in maniera stretta con il Data Client. In particolare persiste una relazione diuno a uno.Paolo Vanacore 566/1539 Pagina 60 di 279
    • Accesso ai Dati di MonitoraggioCacti Cacti Cacti Cacti Cacti Cacti DB DBDB RRD Files RRD Files RRD Files Data Server Data Server Data Server RRDB Data Client Admin Server Fig. 4.4.1 – Data Client ed Admin Server per la gestione della logica di controllo nella gestione dei dati 4.4.1 Servizi di amministrazione dei datiI servizi di amministrazione, che lAdmin Server offre per mezzo di socket, sono iseguenti: • gestione della lista di Data Server poiché ogni Data Client può accedere a più server di monitoraggio, lAdmin Server consente di conoscere e gestire la lista di tali server. La gestione della lista comprende le seguenti, possibili, azioni: ◦ lettura; ◦ aggiunta;Paolo Vanacore 566/1539 Pagina 61 di 279
    • ◦ cancellazione. • gestione lista dei device monitorati da un Data Server per ogni Data Server gestibile è possibile conoscere quali sono i device monitorati; • gestione lista degli rrd associati ad un device per ogni device monitorato è possibile conoscere la lista dei file rrd associati; • gestione dei Monitor lAdmin Server consente la gestione di Monitor, che vengono trattati nel successivo paragrafo, in termini di: ◦ lettura; ◦ aggiunta; ◦ cancellazione. • gestione dei Report Statistici per ogni monitor definito sul Data Client, è possibile, come spiegato successivamente, creare dei Report Statistici. LAdmin Server offre tutti i servizi necessari a gestire tali report. 4.4.2 Temporizzazione delle letture degli rrdUn aspetto importante dellapplicazione riguarda la temporizzazione delle letture deifiles rrd. Tralasciando, per il momento, lapplicazione in sé, è possibile inquadrare ilproblema in termini di “lettore/scrittore” (senza riferimento alcuno al classicoproblema di sincronizzazione).Da un lato vi è lapplicazione di monitoraggio che inserisce/scrive dati allinterno deglirrd, dallaltro abbiamo uno o più client che leggono le informazioni dagli rrd.Per quanto riguarda lo “scrittore” la frequenza di inserimento dei dati è definita, nota ePaolo Vanacore 566/1539 Pagina 62 di 279
    • costante.Dal punto di vista del “lettore” la frequenza delle letture deve essere definita in baseagli scopi del lettore stesso.A scopo desempio, supponiamo di avere un database per cui sono definiti i seguentivalori: tipo dato valore significato step 300 Ogni quanti secondi viene monitorato un dato Ogni quanti dati monitorati viene applicata la funzione pdp_per_row 6 di consolidamento ed il risultato inserito nel database rows 700 Quanti dati il database è in grado di contenere lastupdate 1263662654 Data ultimo aggiornamento (formato Unix-epoch)In base alle considerazioni precedentemente fatte è possibile affermare che il databasemantiene uno storico di  T S  = rows ⋅ step ⋅ pdp_per_row =700⋅300⋅6=1260000sec=350h=14,583 gIl database viene aggiornato ogni:  T D  = step ⋅ pdp_per_row =  300⋅6=1800sec  =  30minIndicato con readingPeriod la frequenza delle letture, è necessario stabilire che:  T D readingPeriodT SCiò è giustificato dal fatto che se la frequenza di lettura fosse inferiore a quella diaggiornamento del database, il lettore non otterrebbe dati utili in quanto non sarebberopresenti nuovi dati rispetto alle letture precedenti.Daltro canto è opportuno che la frequenza di lettura sia inferiore o tuttal più uguale alperiodo di tempo cui lo storico si riferisce. Se così non fosse ci sarebbe un alto rischiodi perdita di dati utili. Inoltre, tenendo presente le latenze introdotte dal processo dilettura dei dati (accentuate dallarchitettura client/server dellapplicazione), è opportunomantenere il valore readingPeriod al di sotto del tempo dello storico con il più altomargine possibile.Paolo Vanacore 566/1539 Pagina 63 di 279
    • La frequenza delle letture (readingPeriod) può essere di due nature: • statica; • dinamica.Ovviamente entrambe le strategie prevedono il rispetto della precedente condizione(appartenenza allintervallo [ T D ,  T S ] ).Una temporizzazione del tipo statica, una volta definita, resta costante nel tempo.Una temporizzazione dinamica potrebbe essere funzione di diversi parametri. Alcuniparametri, ad esempio, potrebbero essere il carico del server, la differenza tra numerodi dati letti ed attesi dal punto di vista del lettore e così via.La strategia adottata prevede una temporizzazione di tipo dinamica basata sullafrequenza di aggiornamento degli rrd e sulla differenza tra “dati letti” e “dati attesi”.In particolare ci si attende di leggere un record per volta e, in tal modo, latemporizzazione tende alla frequenza di aggiornamento degli rrd. Ciò significa cheviene data massima priorità ai client. 4.4.3 Monitor e Report Statistici: il Design Pattern ObserverUn altro importante aspetto riguarda la coerenza dei dati dellrrdb e la gestione deiReport Statistici.Per quanto concerne la coerenza dei dati viene fatto uso di thread, detti Monitor, cui èstata assegnata tale responsabilità. Ad ogni file rrd di interesse viene assegnato unMonitor che, in base alla temporizzazione precedentemente descritta, effettua lerichieste di lettura dei dati al Data Client.È stato adottato il pattern Observer al fine di poter registrare listener ai Monitor epoter, così, gestire i dati letti. Per una descrizione del pattern Observer si rimanda alPaolo Vanacore 566/1539 Pagina 64 di 279
    • paragramo 4.5.2.La seguente porzione di diagramma di classe esplicita questaspetto: Fig. 4.4.3.1 – porzione di diagramma di classe relativo al design pattern Observer adottato per i Monitor ed i Report StatisticiDal diagramma si evince la possibilità di registrare listener ai Monitor. In particolare,tra i listener che vengono registrati vi sono: • RrdbFlusherListener, per la persistenza dei dati nel database rrdb; • RrdbReportListener, responsabili della generazione di report statistici.Circa la classe RrdbReportListener, essa è responsabile di aggregare i dati letti dalPaolo Vanacore 566/1539 Pagina 65 di 279
    • Monitor secondo funzioni statistiche. RrdbReportListener è quindi una composizionedi una Function che viene usata per il consolidamento statistico. 4.5 Presentazione dei datiPer la presentazione dei dati è stata adottata la tecnologia Java Servlet/JSP.Tale scelta ha consentito la realizzazione di due interfacce web: una perlamministrazione dellapplicazione ed una per la sola visualizzazione dei dati.Si riporta di seguito un diagramma dei casi duso che sintetizza tale aspetto: Fig. 4.5.1 – use case diagram sinteticoPaolo Vanacore 566/1539 Pagina 66 di 279
    • Come Web-container è stato utilizzato Apache Tomcat, software Open Sourcesviluppato dallApache Software Foundation.Oltre a Servlet e pagine JSP, si è fatto uso di classi JavaBean. Tali classi Javaprevedono il rispetto della logica dellincapsulamento e cioè prevedono: • definizione del costruttore di default; • visibilità degli attributi private; • metodi accessori e cioè: ◦ metodi getXYZ per ogni attributo XYZ che si vuol rendere leggibile; ◦ metodi setXYZ per ogni attributo XYZ che si vuol rendere scrivibile.Luso di JavaBean consente di estrarre, quanto più possibile, il codice Java dallepagine JSP attraverso luso di particolari tag usati per istanziare e manipolare oggettiJavaBean.La strategia adottata rispecchia quello che è conosciuto come Model 2. Prima dianalizzare tale soluzione, si riporta, per completezza, un accenno al Model 1. 4.5.1 Model 1Il Model 1 è uno dei due approcci introdotti nelle specifiche JSP 0.92 per la struttura diunapplicazione Web.Questo modello è di facile implementazione in quanto prevede che tutto il codice siainserito in pagine JSP. In particolare, in unapplicazione Model 1, le pagine JSP sioccupano di tutto.Il flusso di controllo è pertanto il seguente: • lutente richiede una pagina JSP; • il codice contenuto nella JSP esegue calcoli con eventuale accesso ai dati; • la JSP produce loutput in HTML.Paolo Vanacore 566/1539 Pagina 67 di 279
    • Il seguente schema sintetizza tale modello: 2 Http  1 request JSP Browser 6 5 3 Utente 4 Http  responseFig. 4.5.1.1 – Model 1. Tutto il codice di presentazione, controllo ed accesso ai dati è a carico delle pagine JSP.Esiste una variante del Model 1 che introduce luso di JavaBean al fine di separare lapresentazione dei dati ed il controllo, dallaccesso ai dati.In questo caso, quindi, viene introdotta una suddivisione di responsabilità tra JSP eJavaBean secondo il seguente schema: 2 Http  3 1 request JavaBean JSP 6 Browser 8 7 4 Utente 5 Http  response Fig. 4.5.1.2 – Variante del Model 1. Introduzione di JavaBean per laccesso ai datiPaolo Vanacore 566/1539 Pagina 68 di 279
    • Con questa variante le responsabilità di gestione del flusso di controllo e presentazionerestano a carico delle JSP mentre laccesso ai dati (ad es. a database) è a carico diJavaBean. 4.5.2 Model 2 e Design Pattern MVCIl secondo modello introdotto dalle specifiche JSP 0.92 si basa sul Design PatternMVC (ModelViewController).Per meglio descrivere il pattern MVC è necessario mostrare prima un altro pattern sulquale questultimo si basa: il Design Pattern Observer.Il pattern Observer risolve le classi di problemi in cui vi sono: • un oggetto sorgente di eventi, detto soggetto; • una serie di oggetti, detti osservetori, che si desidera siano informati del verificarsi di eventi del soggetto.La soluzione offerta dal pattern Observer prevede: • uninterfaccia che gli osservatori devono implementare; • una lista di osservatori gestita dal soggetto per la quale offre i metodi per associare nuovi osservatori; • alloccorrenza di un evento il soggetto notifica tutti i propri osservatori.Il seguente diagramma di classe sintetizza il pattern Observer:Paolo Vanacore 566/1539 Pagina 69 di 279
    • Fig. 4.5.2.1 – Diagramma di classe relativo al Design Pattern ObserverIl MVC fa uso del pattern Observer al fine di ottenere una completa separazione delleresponsabilità di: • presentazione dei dati; • gestione del flusso di controllo; • accesso ai dati.Esso è spesso utilizzato nella progettazione di GUI (Graphical User Interface). Le sueentità principali sono: • il Modello. • la Vista; • il Controllore.Il Modello rappresenta lo stato del sistema (modellizza il sistema) per mezzo di oggettie/o strutture dati. La Vista è una rappresentazione del Modello mentre il Controller èun oggetto che si occupa dellinterazione con lutente.Un esempio di pattern MVC può essre il funzionamento di un bottone di unainterfaccia grafica.Paolo Vanacore 566/1539 Pagina 70 di 279
    • In tale esempio il Modello è un oggetto che conserva lo stato del bottone: premuto orilasciato.Possiamo inoltre avere più Viste che rappresentano visivamente loggetto bottone. Unavista può, ad esempio, rappresentare il bottone con un effetto tridimensionale permezzo di ombre.Il Controller, in questo caso, è un oggetto responsabile della gestione degli eventigenerati dallinterazione dellutente con il bottone.Supposto, ad esempio, che lutente effettui un click sul bottone, il Controller intercettalevento “pressione bottone” e richiede al Modello di modificare lo stato del bottone in“premuto”. Una volta che il Modello ha modificato lo stato del bottone, informa tuttele Viste. Queste ultime, quindi, procedono a “ridisegnare” il bottone secondo il suonuovo stato.Si riporta di seguito un diagramma di sequenza per lesempio descritto: Fig. 4.5.2.2 – Squence Diagram relativo allesempio del Design Pattern MVCPaolo Vanacore 566/1539 Pagina 71 di 279
    • Sulla base di quanto detto per il MVC, il Model 2, introdotto dalle specifiche JSP 0.92per la struttura di unapplicazione Web, si basa su tre entità: • pagine JSP alle quali è assegnato il ruolo di Vista; • Servlet Java per le responsabilità di Controller; • JavaBean per il Model.Uno schema che rappresenta il Model 2, contestualizzato allapplicazione realizzata, èil seguente: CONTROLLER 1 Http  request Servlet << 2 ins taz iate MODEL > > Browser Bean Utente 5 6 /s e t 3 get JSP 4 Http  response VIEW Admin rrdb Server Fig. 4.5.2.3 – Model 2 e design pattern MVC. Schema contestualizzato allapplicazione realizzataLa scelta di questo modello ha consentito di separare il codice secondo le seguentilogiche: • codice di accesso ai dati nei JavaBean; • codice per il controllo dellinterazione con lutente nelle Servlet; • codice per la presentazione dei dati nelle pagine JSP.Paolo Vanacore 566/1539 Pagina 72 di 279
    • 4.5.3 JFreeChartAl fine di offrire una confortevole visualizzazione dei dati di monitoraggio e deirelativi report statistici, si è fatto uso della libreria JFreeChart.JFreeChart viene distribuita sotto licenza LGPL (GNU Lesser General PublicLicence – i termini di tale licenza sono visionabili al seguente indirizzo:http://www.gnu.org/licenses/lgpl.html) della Free Software Foundation. La principaledifferenza tra LGPL e la più conosciuta GPL (GNU General Public License) risiedenel fatto che la prima consente di utilizzare qualunque licenza per il software derivato,mentre la seconda richiede che il nuovo software sia anchesso rilasciato sotto GPL. Lequattro libertà fondamentali di R. Stallman sono comunque rispettate.JFreeChart è una libreria scritta interamente in Java ed ha lo scopo di offrire tutti glistrumenti necessari per la rappresentazione di grafici. Sono numerose le tipologie digrafici che è possibile creare, ad es: grafici a torta; istogrammi; serie temporali;diagrammi di Gantt.Altra importante caratteristica sono i formati di esportazione dei grafici, che sono: • JPG (Joint Photografic Experts Group); • PNG (Portable Network Graphic); • PDF (Portable Document Format); • SVG (Scalable Vector Graphics).Due principali entità che definisce JFreeChart sono i Dataset e le Series.I Dataset sono collezioni di Series. Queste ultime sono gli oggetti che mantengono idati da rappresentare. Unassociazione, non del tutto esatta, ma che consente diapprossimare il ruolo di queste due entità, può essere immaginare i Dataset come ungrafico e le Series come le curve rappresentate nel grafico. Esistono vari tipi di Datasete Series in base alla natura dei dati da graficare. Sono disponibili, inoltre, Dataset chePaolo Vanacore 566/1539 Pagina 73 di 279
    • consentono limportazione di dati da Database e file di testo.Un altro aspetto interessante di JFreeChart è la gestione degli eventi che consente direalizzare grafici interattivi. A tal fine è previsto luso di tooltip per la gestione deglieventi 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, ad esempio: • attributi del grafico tramite una delle classi del package plot; • rendering del grafico tramite una delle classi del package renderer; • assi del grafico tramite una delle classi del package axis.Si riportano di seguito alcuni esempi di grafici ottenuti da JFreeChart: Fig. 4.5.3.1 – esempio di grafico a torta generato da JFreeChartPaolo Vanacore 566/1539 Pagina 74 di 279
    • Fig. 4.5.3.2 – esempio di grafico generato da JFreeChart. In questo caso vengono usati due tipi di series differenti: una per listogramma ed una per la curva. Fig. 4.5.3.3 – esempio di grafico stile “tachimetro” generato da JFreeChart. In questo esempio viene usato il MeterPlot del package plot.Paolo Vanacore 566/1539 Pagina 75 di 279
    • 4.6 Architettura completaSi riporta di seguito uno schema che sintetizza lintera architettura dellapplicazionerealizzata: SNMP WiFi Unina       RRD File Net­SNMP CACTI RRDTool Piattaforma LAMP MySQL CactiDB JDBC   Dumper   XML Utente XML DATA SERVER Parser Dump Config Files Dom/XPath Files Socket Browser   XML Socket Dump Files Servlet JSP Parser SAX DATA CLIENT JDBC RRDB ADMIN SERVER Socket Bean Fig. 4.6.1 – schema relativo allintero frameworkPaolo Vanacore 566/1539 Pagina 76 di 279
    • 5 Guida duso dellapplicazione realizzata 5.1 Interfaccia di amministrazioneIl primo passo per accedere allinterfaccia di amministrazione è linserimento diusername e password (fig. 5.5.1). Fig. 5.5.1 – schermata di login per lamministrazione dellapplicazioneIn caso di username e/o password errati, viene mostrato un messaggio derrore (fig.5.5.2). Fig. 5.5.2 – messaggio di errore in caso di username e/o password erratiPaolo Vanacore 566/1539 Pagina 77 di 279
    • Dopo aver effettuato correttamente laccesso, viene mostrata la prima schermatadellapplicazione (fig. 5.5.2). Fig. 5.5.2 – prima schermata per la gestione di un Data ClientIn questa schermata è presente un form centrale atto allinserimento dei dati del DataClient che si desidera gestire. In particolare è necessario inserire: • hostname/ip e porta del Data Client che si desidera gestire.Sempre da questo form è possibile variare il tempo della Sessione. Allo scadere di taleperiodo, di default 1800 secondi, sarà necessario rieseguire il login.Nella fascia alta di questa e delle prossime schermate, è presente il tasto “Logout” attoad effettuare la relativa azione.Inseriti i dettagli del Data Client, una volta premuto sul pulsante “Manage”, si accedePaolo Vanacore 566/1539 Pagina 78 di 279
    • alle schermate di amministrazione dello stesso.La prima schermata di amministrazione presenta due form.Il primo form (fig. 5.5.3) consente di gestire i Data Server associati al Data Client.I server, cioè, da cui il Data Client preleva i dati di monitoraggio. Fig. 5.5.3 – form per la gestione dei server di monitoraggio (Data Server)La parte superiore del form presenta un menu a tendina che contiene gli hostname/ip eporte dei Data Server attualmente associati al Data Client. I due radiobox al di sottodel menu a tendina consentono di: • visualizzare i dettagli del Data Server selezionato (“Show Details” – cfr. par. 5.1.1); • eliminare lassociazione con un Data Server (“Delete”). Poichè questa azione è irreversibile e comporta la perdita di tutti i dati (report statistici e monitor) derivanti dal Data Server, il sistema richiede una conferma.La parte inferiore di questo form consente di associare un nuovo server dimonitoraggio al Data Client. A tal fine è necessario inserire, negli appositi campi,lhostname/ip e la porta del nuovo Data Server e, quindi, premere sul bottone “AddServer”.Paolo Vanacore 566/1539 Pagina 79 di 279
    • Il secondo form (fig. 5.5.4) consente la gestione dei Monitor attivi sul Data Client.Il menu a tendina “# Monitor” consente di selezionare uno dei monitor attivi. Fig. 5.5.4 – form per la gestione dei monitor attiviSelezionato un monitor, il form presenta tutti i relativi dettagli ed, in particolare: • Id numerico, univoco, del monitor (“Monitor #”); • Descrizione del monitor (“Description”); • Hostname/ip e porta del Data Server sul quale risiedono i dati di monitoraggio (“Data Server”); • Pathname dellrrd dal quale il monitor effettua le letture (“Rrd pathname”); • Nome del Data source cui si riferiscono i dati letti dal monitor (“Data Source”); • Risoluzione dellrra cui si riferiscono i dati letti dal monitor (“Resolution”); • Frequenza di aggiornamento del monitor in secondi (“Refresh time”): • Data di ultimo aggiornamento del monitor e relativo Time StampPaolo Vanacore 566/1539 Pagina 80 di 279
    • (“Lastupdate”); • Stato del monitor. I possibili valori sono: ◦ ok – in caso di corretto funzionamento del monitor; ◦ waiting – durante i processi di sincronizzazione del monitor con gli aggiornamenti dellrrd; ◦ Error – in caso di errori. In tal caso viene riportata unulteriore voce “Error details” che consente di conoscere i dettagli dello stato di errore.Un altro elemento del form è il bottone “Submit” che consente, attraverso la selezionedi uno dei due radiobox, “Show Reports” (cfr. par. 5.1.2) e “Delete Monitor”, di gestireil monitor selezionato. La cancellazione del Monitor (“Delete Monitor”) richiede unaconferma in quanto, tale operazione, è irreversibile e comporta la perdita di tutti i datiderivanti dal Monitor (come, ad esempio, i Report Statistici). 5.1.1 Gestione dei Data ServerScegliendo di visualizzare i dettagli di un Data Server (“Show details” – fig. 5.5.3) ilsistema mostra i seguenti form: Fig. 5.1.1.1 – form per la scelta di un device monitoratoPaolo Vanacore 566/1539 Pagina 81 di 279
    • Fig. 5.1.1.2 – form per linserimento del pathname di un generico rrdIl primo form (fig. 5.1.1.1) consente di visualizzare i files rrd associati ai devicemonitorati sul Data Server. Il secondo form (fig. 5.1.1.2) consente di visualizzare idettagli di un generico file rrd residente sul Data Server.Supponendo di scegliere uno dei device presenti nel menu a tendina del primo form(fig. 5.1.1.1), una volta premuto il pulsante “submit”, il sistema mostra una schermatadi questo tipo: Fig. 5.1.1.3 – form con lelenco degli rrd di un device monitoratoIn questa schermata è presente un menu a tendina contenente lelenco di tutti gli rrdassociati al device precedentemente selezionato.Scelto un rrd dallelenco, o inserito un pathname valido ad un rrd nel form di fig.5.1.1.2, viene mostrato il seguente form:Paolo Vanacore 566/1539 Pagina 82 di 279
    • Fig. 5.1.1.4 – form contenente i dettagli di un rrdIn questa schermata è possibile visualizzare i dettagli dellrrd, in alto, che consistonoin: • Pathname – percorso completo al file; • Last update – data di ultimo aggiornamento dellrrd; • Step – frequenza di aggiornamento dellrrd; • Version – versione dellrrd.Nella fascia bassa del form è possibile, tramite i menu a tendina, conoscere i dettaglidei Data Source e dei Round Robin Archives dellrrd selezionato.Per ogni Data Source viene riportato: • Name – nome del data source; • Type – tipo di data source; • Heartbeat – frequenza di aggiornamento del data source; • Validity range – intervallo di possibili valori per il data source.Paolo Vanacore 566/1539 Pagina 83 di 279
    • Per i Round Robin Archives le informazioni sono: • Consolidation Function – tipo di funzione di consolidamento per larchivio; • Pdp per row – relativo valore dellarchivio; • XFileFactor – relativo valore dellarchivio.Per i dettagli sul preciso significato di questi valori si rimanda al paragrafo 3.3.Nella parte bassa del form è presente il bottone “Set Monitor” che consente di attivareun monitor sullrrd, relativamente al data source e rra selezionati.Premendo su “Set Monitor” viene mostrato un sommario del monitor che si staattivando (fig. 5.1.1.5). Da tale sommario è possibile inserire una descrizione daassociare al monitor, al fine di renderlo facilmente identificabile.Premendo sul bottone “Add Monitor” questi viene quindi attivato. Fig. 5.1.1.5 – riassunto di un monitor prima della sua attivazionePaolo Vanacore 566/1539 Pagina 84 di 279
    • 5.1.2 Gestione dei Report statisticiPer ogni Monitor attivo di un determinato Data Client, è possibile definire dei ReportStatistici. In riferimento alla figura. 5.5.4, selezionando la voce “Show Reports”tramite il radiobox e premendo il pulsante “Submit” si accede alla schermata relativaai report per il monitor selezionato (fig. 5.1.2.1). La schermata riporta due formseparati da una linea orizzontale.Il form superiore consente, tramite menu a tendina e radiobox, di: • Visualizzare i dettagli di un report esistente; • Eliminare un report esistente. In tal caso la scelta richiede una conferma. Fig. 5.1.2.1 – schermata relativa alla gestione dei report relativi ad un determinato monitor attivoPaolo Vanacore 566/1539 Pagina 85 di 279
    • Scegliendo di visualizzare i dettagli di un report esistente, il sistema mostra unaschermata con i relativi dettagli.Il form inferiore consente di definire un nuovo report per il monitor precedentementeselezionato.I parametri da impostare, tutti obbligatori, sono: • Function – funzione statistica da utilizzare per il report; • Update Frequence – indica gli intervalli di campionamento dei dati; • Max record – consente di definire quanti valori deve conservare il report; • Start form – data dalla quale il report deve partire; • Description – una descrizione del report.Completata la compilazione del form ed inviato lo stesso tramite pressione del tasto“Add report”, il report sarà aggiunto. 5.1.3 Le briciole di paneDurante la navigazione tra le schermate del portale di amministrazione, è possibileconoscere la propria posizione osservando la fascia alta dello schermo. In questaposizione è presente la successione delle pagine che hanno portato a quella attuale (fig.5.1.3.1). Fig. 5.1.3.1 – briciole di paneOltre ai link che puntano alle pagine precedentemente visitate, per ognuna di queste,vengono indicati i dettagli delle scelte effettuate come, ad esempio: • Hostname/ip e porta del Data Client che si sta gestendo; • Hostname/ip e porta del Data Server selezionato;Paolo Vanacore 566/1539 Pagina 86 di 279
    • • Hostname/ip del Device che si sta gestendo; • Pathname del file rrd del quale si stanno visualizzando i dettagli; • Data Source ed RRA selezionati per un nuovo monitor. 5.2 Interfaccia di visualizzazione dei graficiLa seconda interfaccia consente di visualizzare i grafici relativi ai Monitor ecorrispondenti Report statistici. Fig. 5.2.1 – schermata per la visualizzazione dei graficiQuesta schermata (fig. 5.2.1) presenta un menu principale alla sinistra ed un form per iPaolo Vanacore 566/1539 Pagina 87 di 279
    • settaggi sulla destra.Le voci del menu principale, esclusa la prima che viene trattata di seguito, sono sudue livelli ed in particolare: 1. le voci di primo livello si riferiscono ai Monitor attivi; 2. le voci di secondo livello si riferiscono ai Report definiti sul relativo Monitor.Alla pressione di una voce del menu, viene caricato, nella zona centrale della pagina, ilrelativo grafico in tempo reale. Fig. 5.2.2 – esempio di schermata alla pressione di una voce di menuIl form che è presente in ogni schermata nella fascia destra, “Graphs Settings”,permette di personalizzare la visualizzazione dei grafici. In particolare è possibilescegliere il tipo e la risoluzione dei grafici.I possibili tipi sono i seguenti: • Line – segmenti che uniscono coppie di punti consecutivi; • Spline – interpolazione dei punti tramite spline naturale cubica;Paolo Vanacore 566/1539 Pagina 88 di 279
    • • Bar – istogramma; • Area – larea sottesa dalla curva viene riempita con il colore della curva stessa; • Dot – vengono rappresentati unicamente i punti; • 3DLine – vengono rappresentati i punti ed uniti tramite segmenti cui è applicato un effetto ombra.Attualmente le risoluzioni possibili per i grafici sono: • 320x240 punti – aspect ratio 4:3; • 640x480 punti – aspect ratio 4:3; • 800x600 punti – aspect ratio 4:3; • 1024x768 punti – aspect ratio 4:3; • 1280x1024 punti – aspect ratio 5:4; • 1600x1200 punti – aspect ratio 4:3.Una volta modificate le impostazioni di visualizzazione dei grafici, è necessariopremere il tasto “set” per renderle effettive. Tale tasto è presente nella parte bassa delform dei settaggi.Tornando al menu principale, la prima voce, “Compare”, consente di visualizzarenello stesso grafico più dati (Monitor e/o Report).La schermata (fig. 5.2.3), che si presenta nella fascia centrale, è costituita dallelencodei Report. Fig. 5.2.3 – elenco dei Report e relativi Monitor del “Comparator”Paolo Vanacore 566/1539 Pagina 89 di 279
    • Per ogni Report vengono inoltre visualizzati tutti i relativi Monitor attivi. Perconfrontare più dati è quindi necessario selezionare, tramite relative checkbox, le vocidinteresse.Selezionati i Monitor e/o Report desiderati è necessario premere il tasto “Compare”presente in fondo alla lista. A questo punto sarà mostrato il grafico contenente i dati deiMonitor e/o Report selezionati (fig. 5.2.4). Fig. 5.2.4 – esempio di grafico ottenuto dal confronto di alcuni Monitor e Report.Paolo Vanacore 566/1539 Pagina 90 di 279
    • 6 Considerazioni e conclusioniIl framework realizzato rappresenta uno strumento di monitoraggio passivo che, nelcontesto in cui è attualmente in esercizio, consente di conoscere e quindi valutarediversi parametri di esercizio della rete wireless di Ateneo. A tal proposito è statasegnalata al personale del C.S.I. unanomalia nel funzionamento di alcuni APdellinfrastruttura di Monte SantAngelo che, durante i fine settimana, risultano essereirraggiungibili. È stato possibile verificare che ciò è dovuto ad un WDS, sito neldipartimento di Chimica, che, in ogni fine settimana, “cade”, rendendo linterainfrastruttura a suo carico non funzionante.Grazie allutilizzo del software Cacti è stato raggiunto un ottimo grado di scalabilitàdal punto di vista del monitoraggio e ciò è particolarmente rilevante considerato lostato attuale di espansione della rete wireless di Ateneo.Per quanto concerne lelaborazione statistica dei dati di monitoraggio, lapplicazioneJava realizzata consente, in maniera interattiva ed esulando gli amministratori di retedalla scrittura di script o codice in generale, come richiesto dallo stesso Cacti, didefinire diversi report statistici. È inoltre possibile confrontare i vari report al fine diindividuare eventuali relazioni tra landamento di diverse misurazioni. Un esempio puòessere il confronto tra il numero di autenticazioni ed il numero di utenti connessi o,ancora, il numero di autenticazioni ed il numero di apparati attivi per verificare che ilfunzionamento di questi ultimi non risenta del carico di utenti. Attualmente è possibiledefinire report sulla base delle principali funzioni di statistica descrittiva ed, inparticolare: media; mediana; varianza; deviazione standard; minimo; massimo. A talproposito è auspicabile limplementazione di funzioni di statistica inferenziale alloPaolo Vanacore 566/1539 Pagina 91 di 279
    • scopo di fornire ulteriori strumenti di valutazione che rendano lapplicazione ancor piùcompleta.Un aspetto che si ritiene particolarmente rilevante riguarda linterazione con RRDToolche conferisce allapplicazione ottimi margini di evolvibilità ed interoperabilità.Paolo Vanacore 566/1539 Pagina 92 di 279
    • 7 Appendici 7.1 Messa in esercizio del frameworkLapplicazione consta dei seguenti componenti e relativi files: • Server di monitoraggio / Data Server: ◦ Jar per lesecuzione dellapplicazione; ◦ file XML di configurazione e relativo DTD. • Data Client: ◦ Jar per lesecuzione del DataClient; ◦ file XML di configurazione e relativo DTD. • Interfaccia di amministrazione: ◦ War per il deploy su Tomcat dellinterfaccia di amministrazione; • Interfaccia di visualizzazione dei dati: ◦ War per il deploy su Tomcat dellinterfaccia di visualizzazione dei dati; ◦ file XML di configurazione e relativo DTD. 7.1.1 Data ServerPer ogni server di monitoraggio (dove è installato Cacti) è necessario avviare unDataServer. Il contenuto della cartella con cui è distribuito il DataServer è il seguente: • DataServer.jar; • server_config.dtd; • server_config.xml.Paolo Vanacore 566/1539 Pagina 93 di 279
    • Il primo passo per avviare il server è configurare il relativo file XML,“server_config.xml”. È necessario inserire i seguenti parametri: • serverPort: la porta che si desidera utilizzare per il server; • rrdtoolPath: il pathname completo al binario di RRDTool; • dbName: il nome del database di Cacti; • userName: nome utente per laccesso in lettura al database di Cacti; • userPwd: password dellutente per laccesso in lettura al database di Cacti.Nota: lutente per il database di Cacti deve avere permessi adeguati per la lettura.Impostati i parametri è possibile avviare il DataServer. Supposto che si è posizionatinella cartella in cui risiede il file jar, è possibile eseguire il seguente comando bash: java -jar DataServer.jarDurante la sua esecuzione, il DataServer mostra su stdout diverse informazioni di log.Se si desidera conservare tali informazioni è opportuno redirezionare lo stdout su filedi testo. È quindi possibile usare un comando bash del tipo: java -jar DataServer.jar > logfile &Nota: è necessario avere i giusti permessi per eseguire il DataServer in modo chequesti sia in grado di aprire la porta scelta.Per terminare il DataServer è sufficiente uccidere il relativo processo. Tramite ilcomando netstat -ltup è possibile conoscere lelenco delle porte sulle quali visono processi in ascolto. Da questo elenco si può identificare il PID del DataServer.Successivamente è sufficiente uccidere il processo con il comando kill -9 <PID>dove <PID> è lidentificativo del processo precedentemente identificato.Paolo Vanacore 566/1539 Pagina 94 di 279
    • 7.1.2 Data ClientIl DataClient consta dei seguenti files: • dataclient_config.dtd • dataclient_config.xml • DataClient.jar • rrdb.sqlPer installare il database rrdb è possibile seguire i seguenti passi: • effettuare il login nella CLI (Command Line Inteface) di MySQL tramite il comando bash: mysql -u <username> -p Dove <username> è il nome di un utente con credenziali atte alla creazione di nuovi database ed il parametro -p richiede linserimento della relativa password; • eseguire il seguente comando per lesecuzione dello script sql: mysql> source "</pathname/>rrdb.sql" Dove </pathname/> è il percorso completo al file rrdb.sql.Come per il DataServer è necessario inserire alcuni parametri di configurazione nelfile “dataclient_config.xml”.I parametri da inserire sono i seguenti: • serviceSocket.port: porta per lAdminServer/servizi di amministrazione; • dbName: nome del database rrdb (di default è “rrdb”, cfr. rrdb.sql); • userName: nome utente per la scrittura/lettura sul database rrdb; • userPwd: password dellutente per la scrittura/lettura sul database rrdb.Paolo Vanacore 566/1539 Pagina 95 di 279
    • Nota: è necessario che lutente del database abbia le giuste credenziali per la lettura escrittura sul database rrdb.Lesecuzione e la terminazione del DataClient è analoga a quella del DataServer. Èquindi possibile usare il seguente comando bash per eseguire il DataClient: java -jar DataClient.jar > logfile & 7.1.3 Interfaccia di amministrazioneLinterfaccia di amministrazione viene distribuita come file: WiStatAdmin.war.È quindi necessario eseguire il processo di deploy su Tomcat. È possibile effettuaretale processo accedendo al Tomcat Manager dallinterfaccia web di Tomcat (fig.7.1.3.1). Fig. 7.1.3.1 – deploy tramite file war dallinterfaccia web Tomcat ManagerPaolo Vanacore 566/1539 Pagina 96 di 279
    • Poiché linterfaccia di amministrazione prevede laccesso tramite login, è necessarioaggiungere al file tomcat-users.xml di Tomcat le seguenti informazioni: <role rolename="adminLogin" /> <user username="[nomeutente]" password="[password]" roles="standard,manager,adminLogin" />dove [nomeutente] e [password] sono lutente e relativa password che sidesidera usare per linterfaccia di amministrazione.Nota: linterfaccia di amministrazione può risiedere anche su una macchina diversa daquella che ospita il DataClient. 7.1.4 Interfaccia di visualizzazione dei graficiCome per linterfaccia di amministrazione, anche in questo caso, è necessarioeffettuare il deploy del file WiStat.war su Tomcat.Oltre al file war vengono distribuiti i seguenti files: • wistat_config.dtd; • wistat_config.xml.Nota: entrambi i file devono risiedere in una cartella denominata “.wistat_config”,posizionata nella home directory dellutente con cui viene eseguito Tomcat . Se lutenteè root, ad esempio, i due file devono risiedere nella cartella: “/root/.wistat_config/”.È necessario inserire i parametri di configurazione nel file wistat_config.xml.In particolare, bisogna specificare:Paolo Vanacore 566/1539 Pagina 97 di 279
    • • dbName: il nome del database rrdb ( di default è “rrdb”, cfr. rrdb.sql); • userName: nome utente per la lettura sul database rrdb; • userPwd: password dellutente per la lettura sul database rrdb.Nota: è necessario che lutente del database abbia le giuste credenziali per la letturasul database rrdb.Nota: linterfaccia di visualizzazione dei grafici deve risiedere sulla stessa macchinache ospita il database rrdb.Paolo Vanacore 566/1539 Pagina 98 di 279
    • 7.2 DiagrammiIn questo paragrafo vengono riportati i diagrammi UML ritenuti di maggior rilievo traquelli realizzati. È possibile visionare diagrammi UML maggiormente dettagliati sulladocumentazione in formato elettronico allegata al presente documento. 7.2.1 UML – Use Case DiagramsPaolo Vanacore 566/1539 Pagina 99 di 279
    • 7.2.2 UML – Component DiagramsPaolo Vanacore 566/1539 Pagina 100 di 279
    • 7.2.3 UML – Class DiagramsTutti i diagrammi di classe di seguito riportati rappresentano classi, package eprincipali associazioni, senza dettagli circa i metodi e gli attributi. Tale scelta è dettatadal fatto che i diagrammi di classe completi risultano decisamente troppo grandi dapoter essere quì riportati. È comunque possibile visionare i diagrammi integralmentenella documentazione elettronica allegata. Data Clientit.unina.scope.wistat.dataclientPaolo Vanacore 566/1539 Pagina 101 di 279
    • it.unina.scope.wistat.dataclient.databaseit.unina.scope.wistat.dataclient.rrdPaolo Vanacore 566/1539 Pagina 102 di 279
    • it.unina.scope.wistat.dataclient.netPaolo Vanacore 566/1539 Pagina 103 di 279
    • it.unina.scope.wistat.dataclient.stat Data Serverit.unina.scope.wistat.dataserverit.unina.scope.wistat.databasePaolo Vanacore 566/1539 Pagina 104 di 279
    • it.unina.scope.wistat.dataserver.netPaolo Vanacore 566/1539 Pagina 105 di 279
    • WiStatwistatwistat.controller – Servlets –wistat.databasePaolo Vanacore 566/1539 Pagina 106 di 279
    • wistat.bean – JavaBeans – WiStatAdminwistatadminPaolo Vanacore 566/1539 Pagina 107 di 279
    • wistatadmin.bean – JavaBeans –Paolo Vanacore 566/1539 Pagina 108 di 279
    • wistatadmin.controller – Servlets –wistatadmin.it.unina.scope.wistat.dataclientPaolo Vanacore 566/1539 Pagina 109 di 279
    • wistatadmin.it.unina.scope.wistat.dataclient.netPaolo Vanacore 566/1539 Pagina 110 di 279
    • 7.2.4 UML – Sequence Diagrams i. Multithreading e gestione delle connessioni lato Data Server:Paolo Vanacore 566/1539 Pagina 111 di 279
    • ii. Gestione di una generica richiesta, lato Data Server: iii. Gestione di una richiesta di file XML di dump, lato Data Server:Paolo Vanacore 566/1539 Pagina 112 di 279
    • iv. Sequence diagram relativo al Pattern Observer adottato per la gestione di Monitor e Report Statistici sul Data Client. In questo esempio sono presenti due listener al Monitor: uno di tipo RrdbFlusherListener ed un altro RrdbReportListener. Il primo ha il compito di salvare i dati, dellrrd cui è registrato il monitor, sul database rrdb; il secondo ha il compito di eseguire un consolidamento statistico per mezzo di un generico oggetto Function salvando i risultati nel database rrdb.Paolo Vanacore 566/1539 Pagina 113 di 279
    • 7.2.5 UML – StatechartIn riferimento al processo di parsing tramite SAX ed, in particolare, alla classeRRDAutomata si riporta il relativo statechart. Dal diagramma si evince il meccanismodi costruzione della struttura dellrrd in memoria, per mezzo di uno stack di Objectdappoggio.Paolo Vanacore 566/1539 Pagina 114 di 279
    • 7.2.6 EER DiagramSi riporta di seguito il diagramma EER (Enhanced Entity-Relationship) del databaserrdb realizzato:Paolo Vanacore 566/1539 Pagina 115 di 279
    • 7.3 Documentazione JavaDocPer consentire il riuso del codice e levolvibilità dellapplicazione realizzata, è statagenerata la documentazione JavaDoc a partire dal codice sorgente e relativi commenti.La JavaDoc va quindi a completare la documentazione tecnica realizzata costituita daidiagrammi UML e documentazione interna.Lintera documentazione è integralmente visionabile in formato elettronico. 7.4 Codice SorgenteSegue il codice sorgente dellapplicazione realizzata. Considerata la mole di righe dicodice vengono omessi i commenti relativi alla documentazione JavaDoc.Per ulteriori dettagli si rimanda ai documenti in formato elettronico allegati allapresente tesi. 7.4.1 it.unina.scope.wistat.dataclientpackage it.unina.scope.wistat.dataclient;import it.unina.scope.wistat.dataclient.net.*;import java.net.*;import java.io.*;import java.text.SimpleDateFormat;import java.util.*;public class AdminClientManager implements Runnable{ private Socket incoming; //Socket dedicato al client private List<MonitorThread> monitorThreadList = null; public AdminClientManager(Socket incoming, List<MonitorThread> monitorThreadList){ this.incoming = incoming; this.monitorThreadList = monitorThreadList; } private void log(String toLog){Paolo Vanacore 566/1539 Pagina 116 di 279
    • String time = null; //Stringa per la data ed ora corrente Calendar calendar = Calendar.getInstance(); //Oggetto calendario SimpleDateFormat simpleDataFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //Formato data //Data e lora corrente secondo il formato specificato da //simpleDateFormat time = simpleDataFormat.format(calendar.getTime()); System.out.println(time + "::" + toLog); //Mostra sullo stdout } public void run(){ ObjectInputStream ois = null; //Stream ingresso oggetti generici ObjectOutputStream oos = null; //Stream uscita oggetti generici try{ //Inizializzazione ambiente per la comunicazione con il client ois = new ObjectInputStream(incoming.getInputStream()); //Stream di ingresso per leggere oggetti generici oos = new ObjectOutputStream(incoming.getOutputStream()); //Stream di uscita per scrivere oggetti generici Request request = null; //Rappresenta una richiesta del client request = (Request) ois.readObject(); //Riceve richiesta client log("Admin request::" + incoming.getInetAddress() + ":" + incoming.getPort() + ":" + request);//Log info try { if (request instanceof AddMonitorReq) ((AddMonitorReq)request).sendResponse(oos, monitorThreadList); else if (request instanceof MonitorListReq) ((MonitorListReq)request).sendResponse(oos, monitorThreadList); else if (request instanceof DeleteMonitorReq) (DeleteMonitorReq)request).sendResponse(oos,monitorThreadList); else if (request instanceof DeleteDataServerReq) ((DeleteDataServerReq)request).sendResponse(oos,monitorThreadList); else if (request instanceof ReportListReq) ((ReportListReq)request).sendResponse(oos,monitorThreadList); else if (request instanceof AddReportReq) ((AddReportReq)request).sendResponse(oos,monitorThreadList); else if (request instanceof DeleteReportReq) ((DeleteReportReq)request).sendResponse(oos,monitorThreadList); else request.sendResponse(oos); //Invia risposta } catch (Exception ex){ log("Server activity::" +incoming.getInetAddress()+ ":" + incoming.getPort() + "::Exception::" + ex.toString()); log("Server activity::sending Unknown request to "+ incoming.getInetAddress() + ":" + incoming.getPort()); //LogInfo oos.writeObject( newErrorResponse(ex.getMessage())); } ois.close(); //Chiusura stream input associato a socket oos.close(); //Chiusura stream output associato a socket incoming.close(); //Chiude la socket } catch (Exception ex){ //Log info log("Server activity::error status with "+incoming.getInetAddress()+Paolo Vanacore 566/1539 Pagina 117 di 279
    • ":" + incoming.getPort() + "::Details: " + ex); } }}package it.unina.scope.wistat.dataclient;import java.net.ServerSocket;import java.net.Socket;import java.text.SimpleDateFormat;import java.util.Calendar;import java.util.List;public class AdminServer implements Runnable{ private int port = 0; private List<MonitorThread> monitorThreadList = null; public AdminServer(int port, List<MonitorThread> monitorThreadList){ this.port = port; this.monitorThreadList = monitorThreadList; } private static void log(String toLog){ String time = null; //Stringa per la data ed ora corrente Calendar calendar = Calendar.getInstance(); //Oggetto calendario SimpleDateFormat simpleDataFormat = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss"); //Formato data //Restituisce la data e lora corrente secondo il formato //specificato da simpleDateFormat time = simpleDataFormat.format(calendar.getTime()); System.out.println(time + "::" + toLog); //Mostra sullo stdout } @Override public void run() { int servicesSocketPort = port; //Porta socket servizi admin try { //Socket in attesa di richieste di connessione ServerSocket serverSocket = new ServerSocket(servicesSocketPort); //Log info log("Services Server on port:: " + servicesSocketPort); //Ciclo infinito while(true){ Socket incoming = serverSocket.accept(); //Alloccorrenza di una richiesta di connessione, crea una socket //dedicata al client . Costruisce un oggetto per la gestione della //connessione con il client Runnable clientManager=new AdminClientManager( incoming,monitorThreadList); //Crea un thread per gestione connessione conclient Thread clientManagerThread = new Thread(clientManager); clientManagerThread.start(); //Avvia il thread } } catch (Exception ex) { ex.printStackTrace(); } }}package it.unina.scope.wistat.dataclient;Paolo Vanacore 566/1539 Pagina 118 di 279
    • public class Data { private Double value = null; //Valore del dato private int date = 0; //Data di aggiornamento del dato (Unix Era) public Data (Double value, int date){ this.value = value; this.date = date; } public void setValue(Double value){ this.value = value; } public Double getValue(){ return value; } public void setData(int date){ this.date = date; } public int getDate(){ return date; }}package it.unina.scope.wistat.dataclient;import it.unina.scope.wistat.dataclient.database.Rrdb;import it.unina.scope.wistat.dataclient.stat.*;import java.sql.SQLException;import java.util.Calendar;import java.util.Collections;import java.util.LinkedList;import java.util.List;import java.util.Vector;public class DataClient { private static DataclientConfiguration config = DataclientConfiguration.getInstance(); private static List<MonitorThread> monitorThreadList = null; private static void launchMonitors() throws ClassNotFoundException, SQLException{ Rrdb rrdb = null; //Per la connessione al database rrdb //> Inizializzazione rrdb = new Rrdb(config.getRrdbName(), config.getRrdbUserName(), config.getRrdbUserPwd()); //Database rrdb try { rrdb.connect(); //Connessione allrrdb //Inizializzazione lista bloccante per i monitor monitorThreadList = Collections.synchronizedList( new LinkedList<MonitorThread>() ); //Lettura dei data server salvati sullrrdb Vector<String[]> dataServerListStr = rrdb.queryGetSERVERs(); //Ciclo sui data server salvati for (String[] serverStr : dataServerListStr){ //Hostname/ip del dataserver attuale String serverAddress = serverStr[0]; //Porta dataserver attuale int serverPort = Integer.parseInt(serverStr[1]); //Creazione nuovo DataServerPaolo Vanacore 566/1539 Pagina 119 di 279
    • DataServer server = new DataServer(serverAddress, serverPort); Vector<String[]> rrdListStr = rrdb.queryGetRRDs(serverAddress, serverPort); //Lettura rrd delserver //Ciclo sugli rrd del server corrente for (String[] rrdStr : rrdListStr){ //Pathname dellrrd attuale String rrdPathName = rrdStr[0]; //Lettura ds dellrrd attuale Vector<String[]> dsListStr= rrdb.queryGetDSs(rrdPathName, serverAddress, serverPort); //Ciclo sui ds dellrrd corrente for (String[] dsStr : dsListStr){ //Nome del ds attuale String dsName = dsStr[0]; //Lettura rrd relativi al ds attuale Vector<String[]>rraListStr=rrdb.queryGetRRAs(dsName, rrdPathName,serverAddress,serverPort); //Ciclo sugli rra del ds corrente for (String[] rraStr : rraListStr){ //Nome della cf dellrra attuale String cfType = rraStr[0]; //Risoluzione dellrra attuale int resolution = Integer.parseInt(rraStr[1]); //Descrizione dellrra String rraDescription = rraStr[3]; //Richiesta nuovo monitor RrdMonitor monitor=server.getRrdMonitor( rrdPathName,dsName,cfType, resolution,resolution,rraDescription); //Nuovo Thread per il monitor MonitorThread monitorThread = new MonitorThread(monitor); //Rrdb per il listener sul monitor Rrdb rrdb4listener = new Rrdb(config.getRrdbName(), config.getRrdbUserName(), config.getRrdbUserPwd()); //Nuovo listener sul monitor RrdbFlusherListener flusher = new RrdbFlusherListener( serverAddress, serverPort,rrdPathName, dsName, cfType,resolution, rrdb4listener); //Registrazione listener al monitor monitor.addListener(flusher); //Lettura report del monitor attuale Vector<String[]> reportListStr = rrdb.queryGetReports( cfType,resolution, dsName,rrdPathName, serverAddress,serverPort ); //Ciclo sui report for (String[] reportStr : reportListStr){ int reportId = Integer.parseInt(reportStr[0]); String statFunction = reportStr[1]; String frequenceUpdate = reportStr[2]; int rows = Integer.parseInt(reportStr[3]);Paolo Vanacore 566/1539 Pagina 120 di 279
    • String description = reportStr[4]; try { //Costruzione oggetto per la funzione Function function = Function.getInstance(statFunction); Calendar reportLastUpdate = rrdb.queryGetReportLastUpdate(reportId); RrdbReportListener reportListener = null; //Rrdb per il listener sul monitor rrdb4listener = new Rrdb(config.getRrdbName(), config.getRrdbUserName(),config.getRrdbUserPwd()); reportListener = new RrdbReportListener( frequenceUpdate, reportLastUpdate, serverAddress,serverPort, rrdPathName, dsName, cfType, resolution, reportId, rrdb4listener, function, rows, description ); //Registrazione listner al monitor monitor.addListener(reportListener); } catch(Exception ex){ ex.printStackTrace(); } } //Aggiunta monitor alla lista dei monitor monitorThreadList.add(monitorThread); monitorThread.setPriority(Thread.MAX_PRIORITY); monitorThread.start();//Avvio del monitor } } } } } finally { rrdb.disconnect(); } } public static void main(String[] args) throws ClassNotFoundException, SQLException{ launchMonitors(); //Avvio dei monitor salvati //Costruzione ed avvio thread per il server dei servizi di amministrazione AdminServer adminServer = new AdminServer(config.getSocketPort(), monitorThreadList); Thread adminServerThread = new Thread(adminServer); adminServerThread.start(); }}package it.unina.scope.wistat.dataclient;import java.io.File;import org.w3c.dom.*;import org.xml.sax.ErrorHandler;import org.xml.sax.SAXException;import org.xml.sax.SAXParseException;import javax.xml.parsers.*;Paolo Vanacore 566/1539 Pagina 121 di 279
    • import javax.xml.xpath.*;public class DataclientConfiguration implements ErrorHandler{ private String configPath = null;//Pathname al file xml di config. private int socketPort = 0; //Porta Socket per servizi di admin private String rrdbName = null; //Nome del database rrdb private String rrdbUserName = null; //Nome utente per il database rrdb private String rrdbUserPwd = null;//Password utente database rrdb //Unica istanza della classe ServerConfiguration private static final DataclientConfiguration singleton = new DataclientConfiguration(); private DataclientConfiguration(){ File f = new File (System.getProperty ("java.class.path")); File dir = f.getAbsoluteFile ().getParentFile (); configPath = dir.getAbsolutePath()+"/dataclient_config.xml"; //Factory per il file di configurazione xml DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); //Abilitazione del namespace factory.setValidating(true); //Abilitazione validazione try{ //Builder per il file di configurazione xml DocumentBuilder builder = factory.newDocumentBuilder(); builder.setErrorHandler(this); //Handler per errori di parsing Document doc = builder.parse(configPath);//Parsing xml config. //XPath factory per il file di configurazione xml XPathFactory xpfactory = XPathFactory.newInstance(); //Nuovo xpath per valutare le espressioni XPath XPath xpath = xpfactory.newXPath(); //Lettura porta per la socket dei servizi di amministrazione socketPort = Integer.parseInt( xpath.evaluate("/configuration/serviceSocket/port",doc)); //Lettura nome database per i dati degli rrd rrdbName = xpath.evaluate("/configuration/rrdb/dbName",doc); //Lettura nome utente database per i dati degli rrd rrdbUserName=xpath.evaluate("/configuration/rrdb/userName",doc); //Lettura password utente database per i dati degli rrd rrdbUserPwd=xpath.evaluate("/configuration/rrdb/userPwd",doc); } catch(Exception ex){} } public static DataclientConfiguration getInstance(){ return singleton; } public String getConfigPath(){ return configPath; } public int getSocketPort(){ return socketPort; } public String getRrdbName(){ return rrdbName;} public String getRrdbUserName(){ return rrdbUserName; } public String getRrdbUserPwd(){ return rrdbUserPwd; } @Override public void error(SAXParseException ex) throws SAXException {} @Override public void fatalError(SAXParseException ex) throws SAXException {} @Override public void warning(SAXParseException ex) throws SAXException {}}package it.unina.scope.wistat.dataclient;import it.unina.scope.wistat.dataclient.rrd.RRA;import it.unina.scope.wistat.dataclient.rrd.RRD;import it.unina.scope.wistat.dataclient.rrd.RRDAutomata;import it.unina.scope.wistat.dataserver.net.HostListRequest;Paolo Vanacore 566/1539 Pagina 122 di 279
    • import it.unina.scope.wistat.dataserver.net.HostListResponse;import it.unina.scope.wistat.dataserver.net.HostRequest;import it.unina.scope.wistat.dataserver.net.HostResponse;import it.unina.scope.wistat.dataserver.net.RRDFileResponse;import it.unina.scope.wistat.dataserver.net.XmlDumpFileRequest;import java.io.File;import java.io.IOException;import java.util.LinkedList;import javax.xml.parsers.ParserConfigurationException;import javax.xml.parsers.SAXParser;import javax.xml.parsers.SAXParserFactory;import org.xml.sax.SAXException;public class DataServer { private String serverAddress = null; //Indirizzo del server private int serverPort = 0; //Porta del server public DataServer(String serverAddress, int serverPort){ this.serverAddress = serverAddress; this.serverPort = serverPort; } public String getServerAddress(){ return serverAddress; } public int getServerPort(){ return serverPort;} public boolean equals(Object obj){ if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; DataServer objDataServer = (DataServer) obj; return( serverAddress.equals(objDataServer.getServerAddress()) && serverPort == objDataServer.getServerPort() ); } public LinkedList<Device> getDeviceMonitoredList() throws IOException{ LinkedList<Device> deviceList = null; //Costruzione ed invio della richiesta HostListResponse hlresp = (HostListResponse)(new HostListRequest()).sendRequest(serverAddress, serverPort); //Costruzione LinkedList<Device> a partire dalla risposta del server deviceList = new LinkedList<Device>(); for (HostResponse hr : hlresp.getHostList()) deviceList.add(new Device(hr.getHostname(), hr.getDescription())); return deviceList; } public LinkedList<String> getRRDFilesList(Device device) throws IOException{ HostResponse hresp = null; LinkedList<String> rrdFileList = null; //Costruzione ed invio della richiesta hresp = (HostResponse) (new HostRequest(device.getHostname())).sendRequest( serverAddress, serverPort); //Costruzione della LinkedList a partire dalla risposta del server rrdFileList = new LinkedList<String>(); for ( RRDFileResponse rrdFileResp : hresp.getRrdList() ) rrdFileList.add(rrdFileResp.getRrdPath()); return rrdFileList; } public RRD getRRD(String rrdPath) throws IOException, ParserConfigurationException, SAXException{ RRD rrd = null;Paolo Vanacore 566/1539 Pagina 123 di 279
    • String tmpXmlDir = "tmpXml"; //Cartella temp ove memorizzare lxml File xmlTmpFile = null; //File temporaneo xml String xmlPath = null; //Percorso al file xml new File(tmpXmlDir).mkdir(); //Creazione cartella temporanea per lxml //Creazione file temporaneo per lxml xmlTmpFile = File.createTempFile("tmp", ".xml", new File(tmpXmlDir)); xmlPath = xmlTmpFile.getPath(); try{ //Costruzione ed invio richiesta del file xml new XmlDumpFileRequest(rrdPath,xmlPath).sendRequest(serverAddress, serverPort); //Inizio fase di parsing SAX SAXParserFactory spf = SAXParserFactory.newInstance(); //Abilitazione validazione spf.setValidating(true); //Abilitazione namespace spf.setNamespaceAware(true); SAXParser saxParser = spf.newSAXParser(); //Creazione automa per gestione eventi del parser RRDAutomata rrdConstructor = new RRDAutomata(); //Inizio parsing saxParser.parse(new File(xmlPath), rrdConstructor); //Preleva loggetto rrd costruito dallautoma rrd = rrdConstructor.getRrd(); } finally { //Elimina, in ogni caso il file temporaneo xml xmlTmpFile.delete(); } return rrd; } public RrdMonitor getRrdMonitor(String rrdPath, String dsId, int cfIndex, String description) throws IOException, ParserConfigurationException, SAXException{ int refreshTime; int rrdRefreshTime; int rraPdpPerRow; RrdMonitor monitor = null; RRD rrd = getRRD(rrdPath); /*-> calcolo refreshTime in base allRRD <-*/ rrdRefreshTime = rrd.getStep(); //Frequenza aggiornamento per lrrd RRA rra = rrd.getRraList().get(cfIndex); String cfName = rra.getCf().getType(); //Nome CF rraPdpPerRow = rra.getPdpPerRow(); //pdp_per_row dellrra //Calcolo frequenza aggiornamento monitor refreshTime = rrdRefreshTime * rraPdpPerRow; monitor = new RrdMonitor(new DataServer(serverAddress, serverPort), rrdPath, dsId, cfName, refreshTime, refreshTime, description); return monitor; } public RrdMonitor getRrdMonitor(String rrdPath, String dsId, String cfName, int pdpPerRow, String description) throws IOException, ParserConfigurationException, SAXException{ int refreshTime; int rrdRefreshTime; RrdMonitor monitor = null; RRD rrd = getRRD(rrdPath); /*-> calcolo refreshTime in base allRRD <-*/ rrdRefreshTime = rrd.getStep(); //Frequenza aggiornamento per lrrd //Calcolo frequenza aggiornamento monitorPaolo Vanacore 566/1539 Pagina 124 di 279
    • refreshTime = rrdRefreshTime * pdpPerRow; monitor = new RrdMonitor(new DataServer(serverAddress, serverPort), rrdPath, dsId, cfName, refreshTime, refreshTime, description); return monitor; } public RrdMonitor getRrdMonitor(String rrdPath, String dsName, String cfName, int resolution, int refreshTime, String description){ return new RrdMonitor(new DataServer(serverAddress, serverPort), rrdPath, dsName, cfName, resolution, refreshTime, description); }}package it.unina.scope.wistat.dataclient;public class Device { private String hostname = null; //Hostname/ip del device private String description = null; //Descrizione del device public Device(){ hostname = null; description = null; } public Device(String hostname, String description){ this.description = description; this.hostname = hostname; } public String getHostname(){ return hostname; } public void setHostname(String hostname){this.hostname = hostname; } public String getDescription(){ return description; } public void setDescription(String description){ this.description = description; }}package it.unina.scope.wistat.dataclient;public class MonitorThread extends Thread{ private RrdMonitor monitor = null; public MonitorThread(RrdMonitor monitor){ super(monitor); this.monitor = monitor; } public RrdMonitor getMonitor(){ return monitor; }}package it.unina.scope.wistat.dataclient;import it.unina.scope.wistat.dataclient.database.Rrdb;import java.util.LinkedList;public class RrdbFlusherListener implements RrdMonitorListenerInt{ private String serverAddress=null; //Hostname/ip server dellrrd private int serverPort=0; //Porta del server sul quale risiede lrrd private String rrdPath=null; //Pathname del file rrd private String dsName=null; //Identificativo ds dellrrd associato private String cfName=null; //Nome della cf dellrra associata private int resolution=0; //Risoluzione dellRRAPaolo Vanacore 566/1539 Pagina 125 di 279
    • private Rrdb rrdb=null; //Database per la memorizzazione dei dati public RrdbFlusherListener(String serverAddress, int serverPort, String rrdPath, String dsName, String cfName, int resolution, Rrdb rrdb){ this.serverAddress = serverAddress; this.serverPort = serverPort; this.rrdPath = rrdPath; this.dsName = dsName; this.cfName = cfName; this.resolution = resolution; this.rrdb = rrdb; } public RrdbFlusherListener clone(){ return(new RrdbFlusherListener(serverAddress,serverPort,rrdPath, dsName,cfName.toString(),resolution, new Rrdb(rrdb.getDbName(), rrdb.getUserName(), rrdb.getUserPwd())) ); } @Override public boolean equals(RrdMonitorListenerInt obj){ if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; RrdbFlusherListener objFlusher = (RrdbFlusherListener) obj; return( serverAddress.equals(objFlusher.getServerAddress()) && serverPort == objFlusher.getServerPort() && rrdPath.equals(objFlusher.getRrdPath()) && dsName.equals(objFlusher.getDsName()) && cfName.equals(objFlusher.getCfName()) && resolution == objFlusher.getResolution() ); } public String getServerAddress(){ return serverAddress; } public int getServerPort(){ return serverPort; } public String getRrdPath(){ return rrdPath; } public String getDsName(){ return dsName; } public String getCfName(){ return cfName; } public int getResolution(){ return resolution; } public Rrdb getRrdb(){ return rrdb; } @Override public void dataNotify(LinkedList<Data> dataList){ try { rrdb.connect(); for (Data data : dataList){ try { rrdb.queryInsertData(data.getDate(), cfName, resolution, dsName, rrdPath, serverAddress, serverPort, data.getValue()); } catch (Exception ex){} } } catch(Exception ex){ } finally { rrdb.disconnect(); } } @OverridePaolo Vanacore 566/1539 Pagina 126 di 279
    • public void errorNotify(String errorDetails){} @Override public void exitNotify(){} @Override public void deleteNotify() { try { rrdb.connect(); rrdb.queryDeleteRRA(cfName,resolution,dsName, rrdPath,serverAddress,serverPort); } catch(Exception ex){} finally { rrdb.disconnect(); } }}package it.unina.scope.wistat.dataclient;import it.unina.scope.wistat.dataclient.database.Rrdb;import it.unina.scope.wistat.dataclient.stat.Function;import java.util.Calendar;import java.util.LinkedList;import java.util.regex.Pattern;public class RrdbReportListener implements RrdMonitorListenerInt{ //Espressione regolare per verificare la correttezza della stringa private static final String regExFrequence = "[hdmy]+[1-9]+[0-9]*"; private char frequenceTimeUnit = ; private int frequenceTimeValue = 0; //Hostname/ip del server sul quale risiede lrrd private String serverAddress = null; private int serverPort = 0; //Porta del server sul quale risiede lrrd private String rrdPath = null; //Pathname del file rrd //Identificativo del ds allinterno dellrrd associato private String dsName = null; //Nome della cf allinterno dellrra associato private String cfName = null; private int resolution = 0; //Risoluzione dellRRA private int id = 0; //Id del report private Rrdb rrdb = null; //Database per la memorizzazione dei dati private Calendar reportLastUp = null; //Ultimo aggiornamento report private Function function = null; //Funzione statistica del report private int rows = 0; //Massimo numero di valore da conservare private String description = null; //Descrizione del report public RrdbReportListener(String reportFrequence, Calendar startFrom, String serverAddress, int serverPort, String rrdPath, String dsName, String cfName, int resolution, int id, Rrdb rrdb, Function function, int rows, String description) throws Exception{ //Risoluzione del report Il formato è il seguente: //["h"|"d"|"m"|"y"]number // ad esempio h12 significa ogni 12 ore if ( reportFrequence == null ||!check(reportFrequence)) throw new Exception("Error in report frequence. It must satisfy "+ "the following regular expression: " + regExFrequence); frequenceTimeUnit = reportFrequence.charAt(0); frequenceTimeValue = Integer.parseInt(reportFrequence.substring(1)); this.serverAddress = serverAddress; this.serverPort = serverPort; this.rrdPath = rrdPath;Paolo Vanacore 566/1539 Pagina 127 di 279
    • this.dsName = dsName; this.cfName = cfName; this.resolution = resolution; this.id = id; this.rrdb = rrdb; if (startFrom != null) reportLastUp = (Calendar) startFrom.clone(); this.function = function; this.rows = rows; this.description = description; } public RrdbReportListener clone(){ try{ return(new RrdbReportListener(frequenceTimeUnit+""+ frequenceTimeValue, (Calendar) reportLastUp.clone(), serverAddress, serverPort, rrdPath, dsName, cfName, resolution, id, new Rrdb(rrdb.getDbName(), rrdb.getUserName(), rrdb.getUserPwd()), Function.getInstance(frequenceTimeUnit+""+ frequenceTimeValue), rows, description ) ); }catch(Exception ex){ return null; } } public boolean equals(RrdMonitorListenerInt obj){ if (this == obj) return true; if (obj == null) return false; if (getClass()!= obj.getClass()) return false; RrdbReportListener objReport = (RrdbReportListener) obj; return( frequenceTimeUnit == objReport.getFrequenceTimeUnit() && frequenceTimeValue == objReport.getFrequenceTimeValue() && serverAddress.equals(objReport.getServerAddress()) && serverPort == objReport.getServerPort() && rrdPath.equals(objReport.getRrdPath()) && dsName.equals(objReport.getDsName()) && cfName.equals(objReport.getCfName()) && resolution == objReport.getResolution() && id == objReport.getId() && (function.getFunctionType()).equals( (objReport.getFunction()).getFunctionType()) && rows == objReport.getRows() && description.equals(objReport.getDescription()) ); }Paolo Vanacore 566/1539 Pagina 128 di 279
    • private static boolean check(String reportFrequence){ if (Pattern.matches(regExFrequence, reportFrequence)) return true; else return false; } public char getFrequenceTimeUnit(){ return frequenceTimeUnit; } public int getFrequenceTimeValue(){ return frequenceTimeValue; } public String getServerAddress(){ return serverAddress; } public int getServerPort(){ return serverPort; } public String getRrdPath(){ return rrdPath; } public String getDsName(){ return dsName; } public String getCfName(){ return cfName; } public int getResolution(){ return resolution; } public int getId(){ return id; } public long getLastUpdate(){ return reportLastUp.getTimeInMillis(); } public Function getFunction(){ return function; } public int getRows(){ return rows; } public String getDescription(){ return description; } public Rrdb getRrdb(){ return rrdb; } @Override public void dataNotify(LinkedList<Data> dataList){ Calendar newUpdate = Calendar.getInstance(); boolean isUpTime = false; try{ //Per ogni nuovo dato inserito for (Data data : dataList){ //Inizializzazione data del nuoo dato newUpdate.setTimeInMillis(new Long(data.getDate())*1000); if (reportLastUp == null) reportLastUp = (Calendar) newUpdate.clone();//Calcolo differenza tra la nuova data e lultimo aggiornamento del report DiffDate diffDate = Differences.diffDates(reportLastUp, newUpdate);//Verifica se è arrivato il momento di effettuare laggiornamento report switch (frequenceTimeUnit){ case h: if ( ( diffDate.getDays() > 0 || diffDate.getMonths() > 0 || diffDate.getYears() > 0 ) || ( diffDate.getHours() >= frequenceTimeValue && diffDate.getDays() == 0 && diffDate.getMonths() == 0 && diffDate.getYears() == 0 ) ) isUpTime = true; elsePaolo Vanacore 566/1539 Pagina 129 di 279
    • isUpTime = false; break; case d: if ( ( diffDate.getMonths() > 0 || diffDate.getYears() > 0 ) || ( diffDate.getDays() >= frequenceTimeValue && diffDate.getMonths() == 0 && diffDate.getYears() == 0 ) ) isUpTime = true; else isUpTime = false; break; case m: if ( ( diffDate.getYears() > 0 ) || ( diffDate.getMonths() >= frequenceTimeValue && diffDate.getYears() == 0 ) ) isUpTime = true; else isUpTime = false; break; case y: if ( diffDate.getYears()>=frequenceTimeUnit ) isUpTime = true; else isUpTime = false; break; default: isUpTime = false; } Calendar toData = null; //Se è arrivato il momento di aggiornare il report if (isUpTime && (reportLastUp.getTimeInMillis() < newUpdate.getTimeInMillis())){ //Scorre e calcola la funzione statistica per tutti gli // intervalli di tempo a partire da // [reportLastUp, reportLastUp+frequenceTimeValue] fin quandoPaolo Vanacore 566/1539 Pagina 130 di 279
    • // lestremo destro è >= a newUpdate (data del dato) for (boolean loop = true; loop; ){ //Calcolo estremo destro in base a frequenceUnit toData = (Calendar) reportLastUp.clone(); switch (frequenceTimeUnit){ case h: toData.add(Calendar.HOUR_OF_DAY, +frequenceTimeValue); break; case d: toData.add(Calendar.DAY_OF_MONTH, +frequenceTimeValue); break; case m: toData.add(Calendar.MONTH, +frequenceTimeValue); break; case y: toData.add(Calendar.YEAR, +frequenceTimeValue); break; default: loop = false; } rrdb.connect(); //lettura dati dellrrd LinkedList<Double> valueList = rrdb.queryGetValueRange( cfName, resolution, dsName, rrdPath, serverAddress, serverPort, reportLastUp.getTimeInMillis(), toData.getTimeInMillis() ); for(Double value:function.compute(valueList)) rrdb.queryInsertDataReport(id, toData.getTimeInMillis(),value); rrdb.disconnect(); reportLastUp = (Calendar) toData.clone(); if (reportLastUp.getTimeInMillis() >= newUpdate.getTimeInMillis()) loop = false; } } } }catch (Exception ex){ } finally{ rrdb.disconnect(); } } @Override public void errorNotify(String errorDetails){} @Override public void exitNotify(){} @Override public void deleteNotify() { try { rrdb.connect(); rrdb.queryDeleteReport(id); } catch(Exception ex){} finally { rrdb.disconnect(); } }}class DiffDate{ private int years;Paolo Vanacore 566/1539 Pagina 131 di 279
    • private int months; private int days; private int hours; private int minutes; public DiffDate(){ years = 0; months = 0; days = 0; hours = 0; minutes = 0; } public DiffDate (int years, int months, int days, int hours, int minutes) { this.years = years; this.months = months; this.days = days; this.hours = hours; this.minutes = minutes; } public void setYears (int years){ this.years = years; } public void setMonths (int months){ this.months = months; } public void setDays (int days){ this.days = days; } public void setHoues (int hours){ this.hours = hours; } public void setMinutes (int minutes){ this.minutes = minutes; } public int getYears (){return years; } public int getMonths () {return months; } public int getDays (){return days; } public int getHours(){ return hours; } public int getMinutes(){ return minutes; } public String toString(){ return ( getDays() + "/" + getMonths() + "/" + getYears() + " " + getHours() + ":" + getMinutes() ); }}class Differences{ public static int numMinutes(Calendar cal){ return cal.getActualMaximum(Calendar.MINUTE); } public static int numHours (Calendar cal){ return cal.getActualMaximum(Calendar.HOUR_OF_DAY); } public static int numDays (Calendar cal){ return cal.getActualMaximum (Calendar.DAY_OF_MONTH); } public static int numMinutesPreviusHour(Calendar cal){ Calendar c = (Calendar)cal.clone(); c.roll(Calendar.HOUR_OF_DAY, -1); return c.getActualMaximum(Calendar.MINUTE); } public static int numHoursPreviusDay (Calendar cal){ Calendar c = (Calendar)cal.clone(); c.roll(Calendar.DAY_OF_YEAR, -1); return c.getActualMaximum(Calendar.HOUR_OF_DAY); } public static int numDaysPreviousMonth (Calendar cal){ Calendar c = (Calendar)cal.clone (); c.roll (Calendar.MONTH, -1); return c.getActualMaximum (Calendar.DAY_OF_MONTH); } public static DiffDate diffDates(Calendar beforeDate,Calendar afterDate){ int carryMinutes = 0; int carryHours = 0; int carryDay = 0; int carryMonth = 0; int diffMinutes = afterDate.get(Calendar.MINUTE) - beforeDate.get(Calendar.MINUTE);Paolo Vanacore 566/1539 Pagina 132 di 279
    • if (diffMinutes < 0){ diffMinutes += 60; carryMinutes = 1; } int diffHours = afterDate.get(Calendar.HOUR_OF_DAY) - beforeDate.get(Calendar.HOUR_OF_DAY) - carryMinutes; if (diffHours < 0){ diffHours += 24; carryHours = 1; } int diffday = afterDate.get(Calendar.DAY_OF_MONTH) - beforeDate.get(Calendar.DAY_OF_MONTH) - carryHours; if (diffday < 0){ diffday += numDaysPreviousMonth (afterDate); carryDay = 1; } int diffmonth = afterDate.get(Calendar.MONTH) - beforeDate.get(Calendar.MONTH) - carryDay; if (diffmonth < 0){ diffmonth += 12; carryMonth = 1; } int diffyear = afterDate.get(Calendar.YEAR) - beforeDate.get(Calendar.YEAR) - carryMonth; return new DiffDate(diffyear,diffmonth,diffday,diffHours,diffMinutes); }}package it.unina.scope.wistat.dataclient;import it.unina.scope.wistat.dataserver.net.DataRequest;import it.unina.scope.wistat.dataserver.net.DataResponse;import java.util.*;public class RrdMonitor implements Runnable{ private DataServer server = null; //Server sul quale risiede lrrd private String rrdPath = null; //Pathname allrrd associato private String dsId = null; //Identificativo ds dellrrd associato private String cfName = null; //Nome della cf dellrra associato private int resolution = 0; //Risoluzione dei dati private int refreshTime = 0; //Frequenza daggiornamento in secondi private int refreshFactor = 0; //Fattore per regolare il refresh private int lastUpdate = 0; //Data ultimo aggiornamento (Unix Epoch) private LinkedList<Data> dataList = null; //Lista dei dati private boolean errorStatus; //Eventuale stato derrore del monitor private String errorString = null;//Ultimo, eventuale, errore occorso private String description = null; //Descrizione del monitor //Linked list degli ascoltatori private LinkedList<RrdMonitorListenerInt> listenerList = null; public RrdMonitor(DataServer server, String rrdPath, String dsId, String cfName,int resolution,int refreshTime,String description){ this.server = server; this.rrdPath = rrdPath; this.dsId = dsId; this.cfName = cfName; this.resolution = resolution; this.refreshTime = refreshTime; listenerList = new LinkedList<RrdMonitorListenerInt>(); this.description = description;Paolo Vanacore 566/1539 Pagina 133 di 279
    • } public DataServer getServer(){ return server; } public String getRrdPath(){ return rrdPath; } public String getDsName(){ return dsId; } public String getCfName(){ return cfName; } public int getResolution(){ return resolution; } public int getRefreshTime(){ return refreshTime; } public int getLastUpdate() { return lastUpdate; } public LinkedList<Data> getDataList(){ return dataList; } public boolean getErrorStatus(){ return errorStatus; } public String getErrorString(){ return errorString; } public String getDescription(){ return description; } public synchronized void addListener(RrdMonitorListenerInt listener){ listenerList.add(listener); } public synchronized boolean removeListener(RrdMonitorListenerInt listener){ int count = 0; for (RrdMonitorListenerInt listenerTmp : listenerList){ if (listenerTmp.equals(listener)){ listenerList.remove(count); return true; } count++; } return false; } public synchronized LinkedList<RrdMonitorListenerInt> cloneListenerList() {return (LinkedList<RrdMonitorListenerInt>) listenerList.clone(); } public boolean equals(Object obj){ if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; RrdMonitor objRrdMonitor = (RrdMonitor) obj; return( server.equals(objRrdMonitor.getServer()) && rrdPath.equals(objRrdMonitor.getRrdPath()) && dsId.equals(objRrdMonitor.getDsName()) && cfName.equals(objRrdMonitor.getCfName()) && resolution == objRrdMonitor.getResolution() ); } public void delete(){ for (RrdMonitorListenerInt listener : listenerList) listener.deleteNotify(); } public void run() { boolean exit = false; DataResponse response = null; int oldLastUpdate = 0; LinkedList<Vector<String>> responseList = null; while(!exit){ oldLastUpdate = lastUpdate; errorStatus = false; errorString = null; try{Paolo Vanacore 566/1539 Pagina 134 di 279
    • response = (DataResponse)( new DataRequest(rrdPath, dsId, cfName, resolution, lastUpdate)).sendRequest( server.getServerAddress(), server.getServerPort()); responseList = response.getNumberList(); dataList = null; if (responseList != null){ String value = null; Integer date = null; dataList = new LinkedList<Data>(); for (Vector<String> valueVctr : responseList){ date = Integer.parseInt(valueVctr.get(0)); value = valueVctr.get(1); if (!value.equals("nan")){ dataList.add( new Data(Double.parseDouble( value.replace(",", ".")), date)); lastUpdate = date; } } if (dataList.isEmpty()){ lastUpdate = oldLastUpdate; if (refreshFactor > 0) refreshFactor -= 1; } else { if( (dataList.size() > 1) && (refreshFactor!=(lastUpdate- oldLastUpdate))) refreshFactor += 1; for(RrdMonitorListenerInt listener:listenerList) listener.dataNotify(dataList); } } Thread.sleep( (refreshTime - refreshFactor) * 1000); } catch (InterruptedException ex) { for (RrdMonitorListenerInt listener : listenerList) listener.exitNotify(); exit = true; } catch (Exception ex){ errorStatus = true; errorString = ex.getMessage(); lastUpdate = oldLastUpdate; for (RrdMonitorListenerInt listener : listenerList) listener.errorNotify(errorString); try{ Thread.sleep(refreshTime * 1000); } catch (InterruptedException ex2){ return; } } } }}package it.unina.scope.wistat.dataclient;import java.util.LinkedList;public interface RrdMonitorListenerInt {Paolo Vanacore 566/1539 Pagina 135 di 279
    • public void dataNotify(LinkedList<Data> dataList); public void errorNotify(String errorDetails); public void exitNotify(); public void deleteNotify(); @Override public boolean equals (Object listenerToDelete); public Object clone();} 7.4.2 it.unina.scope.wistat.dataclient.databasepackage it.unina.scope.wistat.dataclient.database;import java.sql.*;import java.util.Vector;public class MysqlDatabase { private String dbName = null; //Nome del Database private String userName = null; //Nome utente per Database private String userPwd = null; //Password utente Database private Connection db = null; //Connessione al Database private boolean connStatus; //Indica lo stato della connessione (true: //connesso; false: non connesso) public MysqlDatabase (String dbName, String userName, String userPwd){ this.dbName = dbName; this.userName = userName; this.userPwd = userPwd; connStatus = false; } public String getDbName(){ return dbName; } public String getUserName(){ return userName; } public String getUserPwd(){ return userPwd; } public void connect() throws ClassNotFoundException, SQLException{ connStatus = false; //Carica driver JDBC Class.forName("com.mysql.jdbc.Driver"); //Effettua la connessione db = DriverManager.getConnection("jdbc:mysql://localhost/" + dbName + "?user=" + userName + "&password=" + userPwd); //Connessione effettuata connStatus = true; } public Vector<String[]> query(String query) throws SQLException { Vector<String[]> result = null; String [] record; int colums = 0; //Statement per lesecuzione della query Statement statement = db.createStatement(); //ResultSet query ResultSet resultSet = statement.executeQuery(query); result = new Vector<String[]>(); //Vettore per i risultati //ResultSetMetaData del risultato della query ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); //Numero di colonne del risultato della queryPaolo Vanacore 566/1539 Pagina 136 di 279
    • colums = resultSetMetaData.getColumnCount(); //Scorre il ResultSet e crea il vettore risultato while(resultSet.next()){ record = new String[colums]; for (int i=0;i<colums; i++) record[i]=resultSet.getString(i+1); result.add( (String[])record.clone() ); } resultSet.close(); //Chiusura ResultSet statement.close(); //Chiusura Statement return result; } public void updateQuery(String query) throws SQLException { Statement stmt = db.createStatement(); stmt.executeUpdate(query); stmt.close(); } public void disconnect() { if (db!=null){ try { db.close(); connStatus = false; } catch (Exception e){ e.printStackTrace(); } } } public boolean getConnectionStatus() { return connStatus; }}package it.unina.scope.wistat.dataclient.database;import java.sql.SQLException;import java.text.DateFormat;import java.text.SimpleDateFormat;import java.util.*;public class Rrdb extends MysqlDatabase{ public Rrdb(String rrdbName, String rrdbUserName, String rrdbUserPwd) { super(rrdbName, rrdbUserName, rrdbUserPwd); } public void queryInsertSERVER(String serverAddress, int serverPort) throws SQLException{ String query = "LOCK TABLES SERVER WRITE;"; this.updateQuery(query); query = "INSERT INTO SERVER VALUES (" + serverAddress + "," + serverPort + ");"; this.updateQuery(query); query = "UNLOCK TABLES;"; this.updateQuery(query); } public Vector<String[]> queryGetSERVERs() throws SQLException{ String query = "SELECT SERVER.Server_Address, SERVER.Server_Port " + "FROM SERVER"; return this.query(query); } public void queryDeleteSERVER(String serverAddress, int serverPort) throws SQLException{ String query = "LOCK TABLES SERVER WRITE;"; this.updateQuery(query);Paolo Vanacore 566/1539 Pagina 137 di 279
    • query = "DELETE FROM SERVER " + "WHERE " + "Server_Address=" + serverAddress + "" + " AND " + "Server_Port=" + serverPort + " LIMIT 1;"; this.updateQuery(query); query = "UNLOCK TABLES;"; this.updateQuery(query); } public void queryInsertRRD(String rrd_FilePathName, String serverAddress, int serverPort, String version, int step) throws SQLException{ String query = "LOCK TABLES RRD WRITE;"; this.updateQuery(query); query = "INSERT INTO RRD VALUES (" + "" + rrd_FilePathName + "," + "" + serverAddress + ", " + "" + serverPort + ", " + "" + version + ", " + step + ");"; this.updateQuery(query); query = "UNLOCK TABLES;"; this.updateQuery(query); } public Vector<String[]> queryGetRRDs(String serverAddress, int serverPort) throws SQLException{ String query = "SELECT RRD.Rrd_FilePathName, RRD.Server_Address, " + "RRD.Server_Port, RRD.Version, RRD.Step FROM " + "SERVER JOIN RRD " + "USING (Server_Address, Server_Port) " + "WHERE " + "Server_Address = " + serverAddress + "" + " AND " + "Server_Port = " + serverPort + ";"; return this.query(query); } public void queryDeleteRRD(String rrd_FilePathName, String serverAddress, int serverPort) throws SQLException{ String query = "LOCK TABLES RRD WRITE;"; this.updateQuery(query); query = "DELETE FROM RRD WHERE " + "Server_Address=" + serverAddress + "" + " AND " + "Server_Port=" + serverPort + " AND " + "Rrd_FilePathName=" + rrd_FilePathName + "" + " LIMIT 1;"; this.updateQuery(query); query = "UNLOCK TABLES;"; this.updateQuery(query); } public void queryInsertDS(String dsName, String rrd_FilePathName, String serverAddress, int serverPort, String type, int heartBeat, Double min, Double max) throws SQLException{ String query = "LOCK TABLES DS WRITE;"; this.updateQuery(query);Paolo Vanacore 566/1539 Pagina 138 di 279
    • if (min.toString().equals("NaN")) min = Double.MAX_VALUE; if (max.toString().equals("NaN")) max = Double.MAX_VALUE; query = "INSERT INTO DS VALUES (" + "" + dsName + ", " + "" + rrd_FilePathName + ", " + "" + serverAddress + ", " + "" + serverPort + ", " + "" + type + ", " + heartBeat + "," + min + "," + max + ");"; this.updateQuery(query); query = "UNLOCK TABLES;"; this.updateQuery(query); } public Vector<String[]> queryGetDSs(String rrd_FilePathName, String serverAddress, int serverPort) throws SQLException{ String query = "SELECT DS.Ds_Name, DS.Rrd_FilePathName, " +"DS.Server_Address, DS.Server_Port, DS.Type, DS.Heartbeat, DS.Min, DS.Max"+" FROM RRD JOIN DS " + "USING (Rrd_FilePathName, Server_Address, Server_Port) " + "WHERE " + "Rrd_FilePathName = " + rrd_FilePathName + "" + " AND " + "Server_Address = " + serverAddress + "" + " AND " + "Server_Port = " + serverPort + ";"; return this.query(query); } public void queryDeleteDS(String dsName, String rrd_FilePathName, String serverAddress, int serverPort) throws SQLException{ String query = "LOCK TABLES DS WRITE;"; this.updateQuery(query); query = "DELETE FROM DS " + "WHERE " + "Server_Address=" + serverAddress + "" + " AND " + "Server_Port=" + serverPort + " AND " + "Rrd_FilePathName=" + rrd_FilePathName + "" + " AND " + "Ds_Name=" + dsName + "" + " LIMIT 1;"; this.updateQuery(query); query = "UNLOCK TABLES;"; this.updateQuery(query); } public void queryInsertRRA(String cfName, int resolution, String dsName, String rrd_FilePathName, String serverAddress, int serverPort, int rows, String description) throws SQLException{ String query = "LOCK TABLES RRA WRITE;"; this.updateQuery(query); query = "INSERT INTO RRA " + "VALUES (" +Paolo Vanacore 566/1539 Pagina 139 di 279
    • "" + cfName + "," + "" + resolution + "," + "" + dsName + "," + "" + rrd_FilePathName + "," + "" + serverAddress + "," + "" + serverPort + "," + "" + rows + "," + "" + description + ");"; this.updateQuery(query); query = "UNLOCK TABLES;"; this.updateQuery(query); } public Vector<String[]> queryGetRRAs(String dsName, String rrd_FilePathName, String serverAddress, int serverPort) throws SQLException{ String query = "SELECT RRA.Rra_CfName, RRA.Rra_Resolution, " + "RRA.Rows, RRA.Description FROM RRA JOIN DS " + "USING (Ds_Name, Rrd_FilePathName, Server_Address, Server_Port)" + " WHERE Ds_Name = " + dsName + "" + " AND " + "Rrd_FilePathName = " + rrd_FilePathName + "" + " AND " + "Server_Address = " + serverAddress + "" + " AND " + "Server_Port = " + serverPort + ";"; return this.query(query); } public void queryDeleteRRA(String cfName, int resolution, String dsName, String rrd_FilePathName, String serverAddress, int serverPort) throws SQLException{ String query = "LOCK TABLES RRA WRITE;"; this.updateQuery(query); query = "DELETE FROM RRA WHERE " + "Server_Address=" + serverAddress + "" + " AND " + "Server_Port=" + serverPort + "" + " AND " + "Rrd_FilePathName=" + rrd_FilePathName + "" + " AND " + "Ds_Name=" + dsName + "" + " AND " + "Rra_CfName=" + cfName + "" + " AND " + "Rra_Resolution=" + resolution + "" + " LIMIT 1;"; this.updateQuery(query); query = "UNLOCK TABLES;"; this.updateQuery(query); } public void queryInsertData(long timeStamp, String cfName, int resolution, String dsName, String rrd_FilePathName, String serverAddress, int serverPort, Double value) throws SQLException{ DateFormat df = new SimpleDateFormat ("yyyy/MM/dd HH:mm:ss"); String data = df.format(new Date(timeStamp*1000)); String query = "CALL " + "insertData(" + "" + data + "," + "" + cfName + "," +Paolo Vanacore 566/1539 Pagina 140 di 279
    • "" + resolution + "," + "" + dsName + "," + "" + rrd_FilePathName + "," + "" + serverAddress + "," + "" + serverPort + "," + "" + value + ");"; this.updateQuery(query); } public LinkedList<Double> queryGetValueRange(String cfName, int resolution, String dsName, String rrd_FilePathname, String serverAddress, int serverPort, long fromDate, long toDate) throws SQLException{ LinkedList<Double> dataList = null; DateFormat df = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss"); String fromDateStr = df.format(fromDate); String toDateStr = df.format(toDate); String query = "SELECT VALUE" + " FROM DATA JOIN RRA " + " USING " + "(Rra_CfName, " + "Rra_Resolution, " + "Ds_Name, " + "Rrd_FilePathName, " + "Server_Address, " + "Server_Port) " + "WHERE " + "Rra_CfName = " + cfName + "" + " AND " + "Rra_Resolution = " + resolution + "" + " AND " + "DS_Name = " + dsName + "" + " AND " + "Rrd_FilePathName = " + rrd_FilePathname + "" + " AND " + "Server_Address = " + serverAddress + "" + " AND " + "Server_Port = " + serverPort + "" + " AND " + "Data_Time >= " + fromDateStr + "" + " AND " + "Data_Time <= " + toDateStr + ";"; Vector<String[]> result = this.query(query); if (result != null){ dataList = new LinkedList<Double>(); for (String[] dataVector : result) if (dataVector != null) for (String dataStr : dataVector) dataList.add(Double.parseDouble(dataStr)); } return dataList; } public int queryInsertReport(String cfName, int resolution, String dsName, String rrd_FilePathName, String serverAddress, int serverPort, String statFunction, String frequenceUpdate, int rows, String description) throws SQLException{ String query = "LOCK TABLES REPORT WRITE;"; this.updateQuery(query);Paolo Vanacore 566/1539 Pagina 141 di 279
    • query = "INSERT INTO REPORT " + "(" + "Rra_CfName, " + "Rra_Resolution, " + "Ds_Name, " + "Rrd_FilePathname, " + "Server_Address, " + "Server_Port, " + "Rows, " + "StatFunction, " + "FrequenceUpdate, " + "Description" + ") " + "VALUES (" + "" + cfName + "," + "" + resolution + "," + "" + dsName + "," + "" + rrd_FilePathName + "," + "" + serverAddress + "," + "" + serverPort + "," + "" + rows + "," + "" + statFunction + "," + "" + frequenceUpdate + "," + "" + description + "" + ");"; this.updateQuery(query); Vector<String[]> responseVectorArrayStr = this.query("SELECT " + " LAST_INSERT_ID() FROM REPORT;"); int responseId = -1; if (responseVectorArrayStr!=null && responseVectorArrayStr.size()!=0){ String[] responseArrayStr = responseVectorArrayStr.get(0); if (responseArrayStr != null && responseArrayStr.length != 0) responseId = Integer.parseInt(responseArrayStr[0]); } query = "UNLOCK TABLES;"; this.updateQuery(query); return responseId; } public Vector<String[]> queryGetReports(String cfName, int resolution, String dsName, String rrd_FilePathName, String serverAddress, int serverPort) throws SQLException{ String query = "SELECT REPORT.Report_Id, REPORT.StatFunction, " + "REPORT.FrequenceUpdate, REPORT.Rows, REPORT.Description " + " FROM REPORT JOIN RRA " + "USING (Rra_CfName, Rra_Resolution, Ds_Name, Rrd_FilePathName, " + "Server_Address, Server_Port) " + "WHERE " + "Rra_CfName = " + cfName + "" + " AND " + "Rra_Resolution = " + resolution + "" + " AND " + "Ds_Name = " + dsName + "" + " AND " + "Rrd_FilePathName = " + rrd_FilePathName + "" + " AND " + "Server_Address = " + serverAddress + "" + " AND " + "Server_Port = " + serverPort + ";";Paolo Vanacore 566/1539 Pagina 142 di 279
    • return this.query(query); } public void queryDeleteReport(int reportId) throws SQLException{ String query = "LOCK TABLES REPORT WRITE;"; this.updateQuery(query); query = "DELETE FROM REPORT WHERE " + "Report_Id=" + reportId + " " + " LIMIT 1;"; this.updateQuery(query); query = "UNLOCK TABLES;"; this.updateQuery(query); } public void queryInsertDataReport(int reportId, long timeStamp, Double value) throws SQLException{ DateFormat df = new SimpleDateFormat ("yyyy/MM/dd HH:mm:ss"); String data = df.format(new Date(timeStamp)); String query = "CALL " + "insertDataReport(" + "" + reportId + "," + "" + data + "," + "" + value + ");"; this.updateQuery(query); } public Calendar queryGetReportLastUpdate(int reportId){ Vector<String[]> date = null; String query = "SELECT MAX(Data_Time) " + "FROM `DATA_REPORT` " + "WHERE " + "Report_Id = " + reportId + ";"; try { date = this.query(query); StringTokenizer dateTok=new StringTokenizer(date.get(0)[0], "-: ."); int year = Integer.parseInt(dateTok.nextToken()); int month = Integer.parseInt(dateTok.nextToken()) - 1; int day = Integer.parseInt(dateTok.nextToken()); int hour = Integer.parseInt(dateTok.nextToken()); int min = Integer.parseInt(dateTok.nextToken()); int sec = Integer.parseInt(dateTok.nextToken()); Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.YEAR, year); calendar.set(Calendar.MONTH, month); calendar.set(Calendar.DAY_OF_MONTH, day); calendar.set(Calendar.HOUR_OF_DAY, hour); calendar.set(Calendar.MINUTE, min); calendar.set(Calendar.SECOND, sec); return calendar; } catch (Exception e) { return null; } }}Paolo Vanacore 566/1539 Pagina 143 di 279
    • 7.4.3 it.unina.scope.wistat.dataclient.netpackage it.unina.scope.wistat.dataclient.net;import it.unina.scope.wistat.dataclient.DataclientConfiguration;import it.unina.scope.wistat.dataclient.MonitorThread;import it.unina.scope.wistat.dataclient.database.Rrdb;import java.io.IOException;import java.io.ObjectOutputStream;import java.sql.SQLException;import java.util.List;import javax.xml.parsers.ParserConfigurationException;import org.xml.sax.SAXException;public class AddDataServerReq implements Request { private static final long serialVersionUID = 1944484435745909620L; private Server newServer = null; public AddDataServerReq(Server newServer){ this.newServer = newServer; } public Server getServer(){ return newServer; } @Override public Response sendRequest(String serverAddr, int serverPort) throws IOException { throw new IOException("sendRequest unsupported on server"); } @Override public void sendResponse(ObjectOutputStream oos) throws IOException, ClassNotFoundException, SQLException { //Configurazione per ottenere i paramentri per lrrdb DataclientConfiguration config=DataclientConfiguration.getInstance(); //Rrdb per eseguire le queryes di aggiornamento Rrdb rrdb = new Rrdb(config.getRrdbName(), config.getRrdbUserName(), config.getRrdbUserPwd()); try { rrdb.connect(); //Connessione allrrdb rrdb.queryInsertSERVER(newServer.getServerAddr(), newServer.getServerPort()); //Inserimento server oos.writeObject(new SuccessResponse());//Invio risposta successo } finally{ rrdb.disconnect(); //In ogni caso si disconnette dallrrdb } } @Override public void sendResponse(ObjectOutputStream oos, List<MonitorThread> monitorThreadList) throws IOException, ParserConfigurationException, SAXException, ClassNotFoundException, SQLException { throw new IOException("unsupported method (use: " + "sendResponse(ObjectOutputStream oos))"); }}package it.unina.scope.wistat.dataclient.net;import it.unina.scope.wistat.dataclient.DataServer;import it.unina.scope.wistat.dataclient.DataclientConfiguration;import it.unina.scope.wistat.dataclient.MonitorThread;Paolo Vanacore 566/1539 Pagina 144 di 279
    • import it.unina.scope.wistat.dataclient.RrdMonitor;import it.unina.scope.wistat.dataclient.RrdbFlusherListener;import it.unina.scope.wistat.dataclient.database.Rrdb;import it.unina.scope.wistat.dataclient.rrd.CF;import it.unina.scope.wistat.dataclient.rrd.DS;import it.unina.scope.wistat.dataclient.rrd.RRA;import it.unina.scope.wistat.dataclient.rrd.RRD;import java.io.IOException;import java.io.ObjectOutputStream;import java.sql.SQLException;import java.util.List;import javax.xml.parsers.ParserConfigurationException;import org.xml.sax.SAXException;public class AddMonitorReq implements Request { private static final long serialVersionUID = 3096142063957086280L; private String rrdPathname; private int step; private int pdpPerRow; private String dsName; private String cfName; private Server dataServer; private String description; @Override public Response sendRequest(String serverAddr, int serverPort) throws IOException { throw new IOException("sendRequest unsupported on server"); } @Override public void sendResponse(ObjectOutputStream oos)throws IOException { throw new IOException("unsupported method (use: sendResponse(oos, " + " monitorThreadList))"); } @Override public void sendResponse(ObjectOutputStream oos, List<MonitorThread> monitorThreadList) throws IOException, ParserConfigurationException, SAXException, ClassNotFoundException, SQLException{ DataclientConfiguration config=DataclientConfiguration.getInstance(); Rrdb rrdb = new Rrdb(config.getRrdbName(), config.getRrdbUserName(), config.getRrdbUserPwd()); DataServer server = new DataServer(dataServer.getServerAddr(), dataServer.getServerPort()); RRD rrd = server.getRRD(rrdPathname); DS dsSelect = null; for (DS ds : rrd.getDsList()) if (ds.getName().equals(dsName)) dsSelect = ds; if (dsSelect == null) throw new IOException("Ds not found!"); RRA rraSelect = null; for (RRA rra : rrd.getRraList()) if ( (rra.getCf().getType().equals(cfName)) && (rra.getPdpPerRow() == pdpPerRow) ) rraSelect = rra; if (rraSelect == null) throw new IOException("Rra not found"); int resolution = step * pdpPerRow; RrdMonitor monitor = server.getRrdMonitor(rrdPathname, dsName, cfName, pdpPerRow, description); CF cf = rraSelect.getCf(); rrdb.connect();Paolo Vanacore 566/1539 Pagina 145 di 279
    • try{ rrdb.queryInsertRRD(rrdPathname, server.getServerAddress(), server.getServerPort(), rrd.getVersion(), rrd.getStep()); } catch(Exception ex){ } finally{ try{ rrdb.queryInsertDS(dsName, rrdPathname, server.getServerAddress(),server.getServerPort(), dsSelect.getDst().toString(),dsSelect.getHeartbeat(), dsSelect.getMin(),dsSelect.getMax()); }catch(Exception ex){ } finally{ try{ rrdb.queryInsertRRA(cf.getType(),resolution,dsSelect.getName(), rrdPathname, server.getServerAddress(), server.getServerPort(), cf.getCfArguments().getRows(), description); } finally{ rrdb.disconnect(); } } } MonitorThread monitorThread = new MonitorThread(monitor); RrdbFlusherListener flusher = new RrdbFlusherListener( server.getServerAddress(), server.getServerPort(), rrdPathname,dsName, cf.getType(), resolution, rrdb); monitor.addListener(flusher); monitorThreadList.add(monitorThread); monitorThread.setPriority(Thread.MAX_PRIORITY); monitorThread.start(); oos.writeObject(new SuccessResponse()); }}package it.unina.scope.wistat.dataclient.net;import it.unina.scope.wistat.dataclient.DataServer;import it.unina.scope.wistat.dataclient.DataclientConfiguration;import it.unina.scope.wistat.dataclient.MonitorThread;import it.unina.scope.wistat.dataclient.RrdMonitor;import it.unina.scope.wistat.dataclient.RrdbReportListener;import it.unina.scope.wistat.dataclient.database.Rrdb;import it.unina.scope.wistat.dataclient.stat.Function;import java.io.IOException;import java.io.ObjectOutputStream;import java.util.Calendar;import java.util.List;public class AddReportReq implements Request { private static final long serialVersionUID = 8900314555054489918L; ReportResp reportToAdd = null; MonitorResp monitorToListen = null; @Override public Response sendRequest(String serverAddr, int serverPort) throws IOException { throw new IOException("sendRequest unsupported on server"); }Paolo Vanacore 566/1539 Pagina 146 di 279
    • @Override public void sendResponse(ObjectOutputStream oos)throws IOException { throw new IOException("unsupported method (use: sendResponse(oos, " + "monitorThreadList))"); } @Override public void sendResponse(ObjectOutputStream oos, List<MonitorThread> monitorThreadList) throws Exception{ DataclientConfiguration config =DataclientConfiguration.getInstance(); Function function = Function.getInstance( reportToAdd.getStatFunction());//Costruzione oggetto funzione //Impostazione data partenza report Calendar reportStartTime = (Calendar) Calendar.getInstance(); reportStartTime.setTimeInMillis(reportToAdd.getStartTimeMillis()); RrdbReportListener reportListener = null; //Rrdb per il listener sul monitor Rrdb rrdb4listener = new Rrdb(config.getRrdbName(), config.getRrdbUserName(), config.getRrdbUserPwd()); try { rrdb4listener.connect(); int reportId = rrdb4listener.queryInsertReport( monitorToListen.getCfType(),monitorToListen.getResolution(), monitorToListen.getDsName(), monitorToListen.getRrdPathname(), monitorToListen.getDataServer().getServerAddr(), monitorToListen.getDataServer().getServerPort(), function.getFunctionType(), reportToAdd.getFrequenceUpdate(), reportToAdd.getRows(), reportToAdd.getDescription() ); rrdb4listener.disconnect(); reportListener = new RrdbReportListener( reportToAdd.getFrequenceUpdate(), reportStartTime, monitorToListen.getDataServer().getServerAddr(), monitorToListen.getDataServer().getServerPort(), monitorToListen.getRrdPathname(), monitorToListen.getDsName(), monitorToListen.getCfType(), monitorToListen.getResolution(), reportId, rrdb4listener, function, reportToAdd.getRows(), reportToAdd.getDescription() ); RrdMonitor rrdMonitor = null; Server server = monitorToListen.getDataServer(); RrdMonitor monitorToReg = new RrdMonitor( new DataServer(server.getServerAddr(), server.getServerPort()),monitorToListen.getRrdPathname(), monitorToListen.getDsName(), monitorToListen.getCfType(), monitorToListen.getResolution(), monitorToListen.getRefresh(), monitorToListen.getDescription() ); synchronized(monitorThreadList) { for (MonitorThread monitorThread : monitorThreadList){ rrdMonitor = monitorThread.getMonitor(); //Registrazione listner al monitor if (rrdMonitor.equals(monitorToReg)) rrdMonitor.addListener(reportListener); } } oos.writeObject(new SuccessResponse());Paolo Vanacore 566/1539 Pagina 147 di 279
    • } finally{ rrdb4listener.disconnect(); } }}package it.unina.scope.wistat.dataclient.net;import it.unina.scope.wistat.dataclient.MonitorThread;import it.unina.scope.wistat.dataclient.stat.Function;import java.io.IOException;import java.io.ObjectOutputStream;import java.sql.SQLException;import java.util.List;import javax.xml.parsers.ParserConfigurationException;import org.xml.sax.SAXException;public class AvailableFunctionsReq implements Request { private static final long serialVersionUID = 6835732647181001644L; @Override public Response sendRequest(String serverAddr, int serverPort) throws Exception { throw new IOException("sendRequest unsupported on server"); } @Override public void sendResponse(ObjectOutputStream oos) throws Exception { AvailableFunctionsResp response = new AvailableFunctionsResp(); for (String functionType : Function.getFunctionsList()) response.add(functionType); oos.writeObject(response); //Invio della risposta } @Override public void sendResponse(ObjectOutputStream oos, List<MonitorThread> monitorThreadList) throws IOException, ParserConfigurationException, SAXException, ClassNotFoundException, SQLException { throw new IOException("unsupported method (use: " + "sendResponse(ObjectOutputStream oos))"); }}package it.unina.scope.wistat.dataclient.net;import java.util.LinkedList;public class AvailableFunctionsResp extends LinkedList<String> implements Response { private static final long serialVersionUID = -3126397999997492404L;}package it.unina.scope.wistat.dataclient.net;import it.unina.scope.wistat.dataclient.DataclientConfiguration;import it.unina.scope.wistat.dataclient.MonitorThread;import it.unina.scope.wistat.dataclient.database.Rrdb;import java.io.IOException;import java.io.ObjectOutputStream;import java.sql.SQLException;import java.util.LinkedList;import java.util.List;Paolo Vanacore 566/1539 Pagina 148 di 279
    • import java.util.Vector;import javax.xml.parsers.ParserConfigurationException;import org.xml.sax.SAXException;public class DataServerListReq implements Request { private static final long serialVersionUID = 4417500257400319882L; @Override public Response sendRequest(String serverAddr, int serverPort) throws IOException { throw new IOException("sendRequest unsupported on server"); } @Override public void sendResponse(ObjectOutputStream oos) throws IOException, ClassNotFoundException, SQLException { //Configurazione per ottenere i paramentri per lrrdb DataclientConfiguration config =DataclientConfiguration.getInstance(); //Rrdb per prelevare la lista di server Rrdb rrdb = new Rrdb(config.getRrdbName(), config.getRrdbUserName(), config.getRrdbUserPwd()); try { rrdb.connect(); //Connessione allrrdb //Query per ottenere la lista dei server Vector<String[]> dataServerVector = rrdb.queryGetSERVERs(); //LinkedList dei Server per la risposta LinkedList<Server> dataServerList = new LinkedList<Server>(); //Costruzione lista di server per la risposta for (String[] serverStr : dataServerVector) dataServerList.add(new Server(serverStr[0], Integer.parseInt(serverStr[1]))); //Invio risposta oos.writeObject(new DataServerListResp(dataServerList)); } finally{ rrdb.disconnect(); //In ogni caso si disconnette dallrrdb } } @Override public void sendResponse(ObjectOutputStream oos, List<MonitorThread> monitorThreadList) throws IOException, ParserConfigurationException, SAXException, ClassNotFoundException, SQLException { throw new IOException("unsupported method (use: " + "sendResponse(ObjectOutputStream oos))"); }}package it.unina.scope.wistat.dataclient.net;import java.util.LinkedList;public class DataServerListResp implements Response { private static final long serialVersionUID = 6387195717740393238L; private LinkedList<Server> dataServerList = null; public DataServerListResp(LinkedList<Server> dataServerList){ this.dataServerList = dataServerList; } public LinkedList<Server> getDataServerList(){ return dataServerList; }}package it.unina.scope.wistat.dataclient.net;Paolo Vanacore 566/1539 Pagina 149 di 279
    • import it.unina.scope.wistat.dataclient.DataclientConfiguration;import it.unina.scope.wistat.dataclient.MonitorThread;import it.unina.scope.wistat.dataclient.RrdMonitor;import it.unina.scope.wistat.dataclient.database.Rrdb;import java.io.IOException;import java.io.ObjectOutputStream;import java.sql.SQLException;import java.util.LinkedList;import java.util.List;public class DeleteDataServerReq implements Request{ private Server serverToDelete = null; private static final long serialVersionUID = 6726545229344270109L; public DeleteDataServerReq(Server serverToDelete){ this.serverToDelete = serverToDelete; } public Server getServer(){return serverToDelete; } @Override public Response sendRequest(String serverAddr, int serverPort) throws IOException{ throw new IOException("sendRequest is unsupported on server"); } @Override public void sendResponse(ObjectOutputStream oos) throws IOException{ throw new IOException("unsupported method (use: sendResponse(oos, " + "monitorThreadList))"); } @Override public void sendResponse(ObjectOutputStream oos, List<MonitorThread> monitorThreadList) throws IOException, ClassNotFoundException, SQLException { //Configurazione per ottenere i paramentri per lrrdb DataclientConfiguration config=DataclientConfiguration.getInstance(); //Rrdb per eseguire le queryes di aggiornamento Rrdb rrdb = new Rrdb(config.getRrdbName(), config.getRrdbUserName(), config.getRrdbUserPwd()); try { rrdb.connect(); //Connessione allrrdb //Cancellazione server rrdb.queryDeleteSERVER(serverToDelete.getServerAddr(), serverToDelete.getServerPort()); synchronized(monitorThreadList) { int count = 0; LinkedList<Integer> indexOfMonitorToDelete = new LinkedList<Integer>(); if (monitorThreadList.size() != 0){ for(MonitorThread monitorThread:monitorThreadList){ RrdMonitor rrdMonitor = monitorThread.getMonitor(); if ((( rrdMonitor.getServer() ).getServerAddress() ).equals(serverToDelete.getServerAddr()) && rrdMonitor.getServer().getServerPort() == serverToDelete.getServerPort() ){ rrdMonitor.delete(); monitorThread.interrupt(); indexOfMonitorToDelete.add(count); }Paolo Vanacore 566/1539 Pagina 150 di 279
    • ++count; } count = 0; for (Integer x : indexOfMonitorToDelete){ monitorThreadList.remove(x.intValue()-count); ++count; } } } oos.writeObject(new SuccessResponse());//Invio rispostasuccesso } finally{ rrdb.disconnect(); //In ogni caso si disconnette dallrrdb } }}package it.unina.scope.wistat.dataclient.net;import it.unina.scope.wistat.dataclient.DataServer;import it.unina.scope.wistat.dataclient.MonitorThread;import it.unina.scope.wistat.dataclient.RrdMonitor;import java.io.IOException;import java.io.ObjectOutputStream;import java.util.List;public class DeleteMonitorReq implements Request { private static final long serialVersionUID = -5580509393480619764L; private MonitorResp monitorToDelete = null; public DeleteMonitorReq(MonitorResp monitorToDelete){ this.monitorToDelete = monitorToDelete; } @Override public Response sendRequest(String serverAddr, int serverPort) throws IOException{ throw new IOException("sendRequest is unsupported on server"); } @Override public void sendResponse(ObjectOutputStream oos)throws IOException { throw new IOException("unsupported method (use: sendResponse(oos, " + "monitorThreadList))"); } @Override public void sendResponse(ObjectOutputStream oos, List<MonitorThread> monitorThreadList) throws IOException{ RrdMonitor rrdMonitorToDelete = new RrdMonitor( new DataServer ( monitorToDelete.getDataServer().getServerAddr(), monitorToDelete.getDataServer().getServerPort() ), monitorToDelete.getRrdPathname(), monitorToDelete.getDsName(), monitorToDelete.getCfType(), monitorToDelete.getResolution(), monitorToDelete.getRefresh(), monitorToDelete.getDescription() ); synchronized(monitorThreadList) {Paolo Vanacore 566/1539 Pagina 151 di 279
    • int count = 0; if (monitorThreadList.size() != 0){ for (MonitorThread monitorThread : monitorThreadList){ RrdMonitor rrdMonitor = monitorThread.getMonitor(); if (rrdMonitor.equals(rrdMonitorToDelete)){ rrdMonitor.delete(); monitorThread.interrupt(); } else ++count; } monitorThreadList.remove(count); } } oos.writeObject(new SuccessResponse()); //Invio risposta successo }}package it.unina.scope.wistat.dataclient.net;import it.unina.scope.wistat.dataclient.DataServer;import it.unina.scope.wistat.dataclient.DataclientConfiguration;import it.unina.scope.wistat.dataclient.MonitorThread;import it.unina.scope.wistat.dataclient.RrdMonitor;import it.unina.scope.wistat.dataclient.RrdbReportListener;import it.unina.scope.wistat.dataclient.database.Rrdb;import it.unina.scope.wistat.dataclient.stat.Function;import java.io.IOException;import java.io.ObjectOutputStream;import java.util.List;public class DeleteReportReq implements Request { private static final long serialVersionUID = 3096142063957086280L; private ReportResp reportToDelete = null; @Override public Response sendRequest(String serverAddr, int serverPort) throws IOException { throw new IOException("sendRequest unsupported on server"); } @Override public void sendResponse(ObjectOutputStream oos)throws IOException { throw new IOException("unsupported method (use: sendResponse(oos, " + "monitorThreadList))"); } @Override public void sendResponse(ObjectOutputStream oos, List<MonitorThread> monitorThreadList) throws Exception{ DataclientConfiguration config=DataclientConfiguration.getInstance(); Rrdb rrdb = new Rrdb(config.getRrdbName(), config.getRrdbUserName(), config.getRrdbUserPwd()); MonitorResp monitor = reportToDelete.getMonitor(); Server dataServer = monitor.getDataServer(); DataServer server = new DataServer(dataServer.getServerAddr(), dataServer.getServerPort()); try { rrdb.connect(); rrdb.queryDeleteReport(reportToDelete.getReportId()); rrdb.disconnect(); RrdbReportListener reportListenerToDelete = new RrdbReportListener(Paolo Vanacore 566/1539 Pagina 152 di 279
    • reportToDelete.getFrequenceUpdate(), null, server.getServerAddress(), server.getServerPort(), monitor.getRrdPathname(), monitor.getDsName(), monitor.getCfType(), monitor.getResolution(), reportToDelete.getReportId(), null, Function.getInstance(reportToDelete.getStatFunction()), reportToDelete.getRows(),reportToDelete.getDescription() ); RrdMonitor rrdMonitor = null; synchronized(monitorThreadList) { for (MonitorThread monitorThread : monitorThreadList){ rrdMonitor = monitorThread.getMonitor(); rrdMonitor.removeListener(reportListenerToDelete); } } oos.writeObject(new SuccessResponse()); } finally{ rrdb.disconnect(); } }}package it.unina.scope.wistat.dataclient.net;import it.unina.scope.wistat.dataclient.DataServer;import it.unina.scope.wistat.dataclient.Device;import it.unina.scope.wistat.dataclient.MonitorThread;import java.io.IOException;import java.io.ObjectOutputStream;import java.sql.SQLException;import java.util.LinkedList;import java.util.List;import javax.xml.parsers.ParserConfigurationException;import org.xml.sax.SAXException;public class DeviceListReq implements Request { private static final long serialVersionUID = 2368692290753088537L; private Server dataServerSet = null; public DeviceListReq(Server dataServerSet){ this.dataServerSet = dataServerSet; } @Override public Response sendRequest(String serverAddr, int serverPort) throws IOException { throw new IOException("sendRequest is unsupported on server"); } @Override public void sendResponse(ObjectOutputStream oos) throws IOException { DataServer dataServer = new DataServer (dataServerSet.getServerAddr(), dataServerSet.getServerPort()); LinkedList<Device> deviceList = dataServer.getDeviceMonitoredList(); DeviceListResp response = new DeviceListResp(); for (Device device : deviceList) response.add(new MonitoredDevice(device.getHostname(), device.getDescription())); oos.writeObject(response); //Invio della risposta } @Override public void sendResponse(ObjectOutputStream oos,Paolo Vanacore 566/1539 Pagina 153 di 279
    • List<MonitorThread> monitorThreadList) throws IOException, ParserConfigurationException,SAXException, ClassNotFoundException, SQLException { throw new IOException("unsupported method (use: " + " sendResponse(ObjectOutputStream oos))"); }}package it.unina.scope.wistat.dataclient.net;import java.util.LinkedList;public class DeviceListResp extends LinkedList<MonitoredDevice> implements Response{ private static final long serialVersionUID = 2300464095062479458L;}package it.unina.scope.wistat.dataclient.net;import java.io.Serializable;public class DsResp implements Serializable{ private static final long serialVersionUID = -1902596221474684510L; private String name = null; private String type = null; private int heartbeat = 0; private double min = 0.0; private double max = 0.0; public DsResp(String name, String type, int heartbeat, double min, double max){ this.name = name; this.type = type; this.heartbeat = heartbeat; this.min = min; this.max = max; } public String getName(){return name;} public String getType(){return type;} public Integer getHeartbeat(){return heartbeat;} public Double getMin(){return min;} public Double getMax(){return max;}}package it.unina.scope.wistat.dataclient.net;public class ErrorResponse implements Response { private static final long serialVersionUID = -6010196409281733551L; private String errorDetails = null; public ErrorResponse(String errorDetails){ this.errorDetails = errorDetails; } public String getErrorDetails(){ return errorDetails; }}package it.unina.scope.wistat.dataclient.net;import java.io.Serializable;public class MonitoredDevice implements Serializable{ private static final long serialVersionUID = 3906797826813056798L;Paolo Vanacore 566/1539 Pagina 154 di 279
    • private String hostname = null; private String description = null; public MonitoredDevice(String hostname, String description){ this.hostname = hostname; this.description = description; } public String getHostname(){ return hostname; } public String getDescription(){ return description; }}package it.unina.scope.wistat.dataclient.net;import it.unina.scope.wistat.dataclient.DataServer;import it.unina.scope.wistat.dataclient.MonitorThread;import it.unina.scope.wistat.dataclient.RrdMonitor;import java.io.IOException;import java.io.ObjectOutputStream;import java.util.List;public class MonitorListReq implements Request { private static final long serialVersionUID = 8494720599394685464L; @Override public Response sendRequest(String serverAddr, int serverPort) throws Exception { throw new IOException("sendRequest is unsupported on server"); } @Override public void sendResponse(ObjectOutputStream oos) throws Exception { throw new IOException("unsupported method (use: sendResponse(oos, " + "monitorThreadList))"); } @Override public void sendResponse(ObjectOutputStream oos, List<MonitorThread> monitorThreadList) throws IOException{ MonitorListResp response = new MonitorListResp(); synchronized(monitorThreadList) { for (MonitorThread monitorThread : monitorThreadList){ RrdMonitor rrdMonitor = monitorThread.getMonitor(); DataServer server = rrdMonitor.getServer(); response.add(new MonitorResp( rrdMonitor.getRrdPath(), new Server( server.getServerAddress(),server.getServerPort()), rrdMonitor.getDsName(), rrdMonitor.getCfName(), rrdMonitor.getRefreshTime(),rrdMonitor.getResolution(), rrdMonitor.getLastUpdate(),rrdMonitor.getErrorStatus(), rrdMonitor.getErrorString(),rrdMonitor.getDescription() ) ); } } oos.writeObject(response); //Invio della risposta }}package it.unina.scope.wistat.dataclient.net;import java.util.LinkedList;Paolo Vanacore 566/1539 Pagina 155 di 279
    • public class MonitorListResp extends LinkedList<MonitorResp>implements Response { private static final long serialVersionUID = 4933978189308201591L;}package it.unina.scope.wistat.dataclient.net;public class MonitorResp implements Response { private static final long serialVersionUID = 6652832901015254490L; private String rrdPathname; private Server dataServer; private String dsName; private String cfType; private int refresh; private int resolution; private int lastupdate; private boolean errorStatus; private String errorDetails; private String description; public MonitorResp(String rrdPathname, Server dataServer, String dsName, String cfType, int refresh, int resolution, int lastupdate, boolean errorStatus, String errorDetails, String description){ this.rrdPathname = rrdPathname; this.dataServer = dataServer; this.dsName = dsName; this.cfType = cfType; this.refresh = refresh; this.resolution = resolution; this.lastupdate = lastupdate; this.errorStatus = errorStatus; this.errorDetails = errorDetails; this.description = description; } public String getRrdPathname(){ return rrdPathname; } public Server getDataServer(){ return dataServer; } public String getDsName(){ return dsName; } public String getCfType(){ return cfType; } public int getRefresh(){ return refresh; } public int getResolution(){ return resolution; } public int getLastupdate(){ return lastupdate; } public boolean getErrorStatus(){ return errorStatus; } public String getErrorDetails(){ return errorDetails; } public String getDescription(){ return description; }}package it.unina.scope.wistat.dataclient.net;import it.unina.scope.wistat.dataclient.DataServer;import it.unina.scope.wistat.dataclient.MonitorThread;import it.unina.scope.wistat.dataclient.RrdMonitor;import it.unina.scope.wistat.dataclient.RrdMonitorListenerInt;import it.unina.scope.wistat.dataclient.RrdbReportListener;import java.io.IOException;import java.io.ObjectOutputStream;import java.util.List;public class ReportListReq implements Request {Paolo Vanacore 566/1539 Pagina 156 di 279
    • private static final long serialVersionUID = -2233175135204446307L; private MonitorResp monitor = null; @Override public Response sendRequest(String serverAddr, int serverPort) throws Exception { throw new IOException("sendRequest is unsupported on server"); } @Override public void sendResponse(ObjectOutputStream oos) throws Exception { throw new IOException("unsupported method (use: sendResponse(oos, " + "monitorThreadList))"); } public void sendResponse(ObjectOutputStream oos, List<MonitorThread> monitorThreadList) throws IOException{ ReportListResp response = new ReportListResp(); RrdMonitor rrdMonitorReq = new RrdMonitor( new DataServer(monitor.getDataServer().getServerAddr(), monitor.getDataServer().getServerPort()), monitor.getRrdPathname(), monitor.getDsName(), monitor.getCfType(), monitor.getResolution(), monitor.getRefresh(), monitor.getDescription() ); synchronized(monitorThreadList) { for (MonitorThread monitorThread : monitorThreadList){ RrdMonitor rrdMonitor = monitorThread.getMonitor(); if (rrdMonitor.equals(rrdMonitorReq)) for (RrdMonitorListenerInt listener : rdMonitor.cloneListenerList()) if (listener instanceof RrdbReportListener) response.add(new ReportResp( monitor, ((RrdbReportListener) listener).getId(), ((RrdbReportListener) listener).getFunction().getFunctionType(), ((RrdbReportListener) listener).getFrequenceTimeUnit() + "" + ((RrdbReportListener) listener).getFrequenceTimeValue(), ((RrdbReportListener) listener).getRows(), ((RrdbReportListener) listener).getLastUpdate(), ((RrdbReportListener) listener).getDescription() ) ); } } oos.writeObject(response); //Invio della risposta }}package it.unina.scope.wistat.dataclient.net;import java.util.LinkedList;public class ReportListResp extends LinkedList<ReportResp> implements Response { private static final long serialVersionUID = 665944430100264043L;}package it.unina.scope.wistat.dataclient.net;public class ReportResp implements Response { private static final long serialVersionUID = 8564783838070322444L; private MonitorResp monitor = null; private int reportId = 0; private String statFunction = null;Paolo Vanacore 566/1539 Pagina 157 di 279
    • private String frequenceUpdate = null; private int rows = 0; private long startTimeMillis = 0; private String description = null; public ReportResp(MonitorResp monitor, int reportId, String statFunction, String frequenceUpdate, int rows, long startTimeMillis, String description){ this.monitor = monitor; this.reportId = reportId; this.statFunction = statFunction; this.frequenceUpdate = frequenceUpdate; this.rows = rows; this.startTimeMillis = startTimeMillis; this.description = description; } public MonitorResp getMonitor(){ return monitor; } public int getReportId(){ return reportId; } public String getStatFunction(){ return statFunction; } public String getFrequenceUpdate(){ return frequenceUpdate; } public int getRows(){ return rows; } public long getStartTimeMillis(){ return startTimeMillis; } public String getDescription(){ return description; }}package it.unina.scope.wistat.dataclient.net;import it.unina.scope.wistat.dataclient.MonitorThread;import java.io.ObjectOutputStream;import java.io.Serializable;import java.util.List;public interface Request extends Serializable { public Response sendRequest(String serverAddr, int serverPort) throws Exception; public void sendResponse(ObjectOutputStream oos) throws Exception; public void sendResponse(ObjectOutputStream oos, List<MonitorThread> monitorThreadList) throws Exception;}package it.unina.scope.wistat.dataclient.net;import java.io.Serializable;public interface Response extends Serializable {}package it.unina.scope.wistat.dataclient.net;import java.io.Serializable;public class RraResp implements Serializable{ private static final long serialVersionUID = 8029397766899303172L; private String cf = null; private int pdpPerRow = 0; private int rows = 0; private double xff = 0.0; public RraResp(String cf, int pdpPerRow, int rows, double xff){ this.cf = cf; this.pdpPerRow = pdpPerRow;Paolo Vanacore 566/1539 Pagina 158 di 279
    • this.rows = rows; this.xff = xff; } public String getCf(){ return cf; } public int getPdpPerRow(){ return pdpPerRow; } public int getRows(){ return rows; } public double getXff(){ return xff; }}package it.unina.scope.wistat.dataclient.net;import it.unina.scope.wistat.dataclient.DataServer;import it.unina.scope.wistat.dataclient.Device;import it.unina.scope.wistat.dataclient.MonitorThread;import java.io.IOException;import java.io.ObjectOutputStream;import java.sql.SQLException;import java.util.LinkedList;import java.util.List;import javax.xml.parsers.ParserConfigurationException;import org.xml.sax.SAXException;public class RrdDeviceListReq implements Request { private static final long serialVersionUID = 913262712126181544L; private MonitoredDevice device; private Server dataServerSet; public RrdDeviceListReq(Server dataServerSet, MonitoredDevice device){ this.dataServerSet = dataServerSet; this.device = device; } @Override public Response sendRequest(String serverAddr, int serverPort) throws IOException { throw new IOException("sendRequest is unsupported on server"); } @Override public void sendResponse(ObjectOutputStream oos) throws IOException { DataServer dataServer = new DataServer (dataServerSet.getServerAddr(), dataServerSet.getServerPort()); LinkedList<String> rrdDeviceList = dataServer.getRRDFilesList( new Device(device.getHostname(), device.getDescription())); RrdDeviceListResp response = new RrdDeviceListResp(); for (String rrd : rrdDeviceList) response.add(rrd); oos.writeObject(response); //Invio della risposta } @Override public void sendResponse(ObjectOutputStream oos, List<MonitorThread> monitorThreadList) throws IOException, ParserConfigurationException, SAXException, ClassNotFoundException, SQLException { throw new IOException("unsupported method (use: " + "sendResponse(ObjectOutputStream oos))"); }}Paolo Vanacore 566/1539 Pagina 159 di 279
    • package it.unina.scope.wistat.dataclient.net;import java.util.LinkedList;public class RrdDeviceListResp extends LinkedList<String> implements Response { private static final long serialVersionUID = 7746097408574462762L;}package it.unina.scope.wistat.dataclient.net;import it.unina.scope.wistat.dataclient.DataServer;import it.unina.scope.wistat.dataclient.MonitorThread;import it.unina.scope.wistat.dataclient.rrd.DS;import it.unina.scope.wistat.dataclient.rrd.RRA;import it.unina.scope.wistat.dataclient.rrd.RRD;import java.io.IOException;import java.io.ObjectOutputStream;import java.sql.SQLException;import java.util.LinkedList;import java.util.List;import javax.xml.parsers.ParserConfigurationException;import org.xml.sax.SAXException;public class RrdReq implements Request { private static final long serialVersionUID = -3396668592614646499L; private Server dataServerSet = null; private String rrdPathname; public RrdReq(Server dataServerSet, String rrdPathname){ this.rrdPathname = rrdPathname; this.dataServerSet = dataServerSet; } @Override public Response sendRequest(String serverAddr, int serverPort) throws IOException { throw new IOException("sendRequest is unsupported on server"); } @Override public void sendResponse(ObjectOutputStream oos) throws IOException, ParserConfigurationException, SAXException { DataServer dataServer = new DataServer( dataServerSet.getServerAddr(), dataServerSet.getServerPort()); RRD rrd = dataServer.getRRD(rrdPathname); LinkedList<DsResp> dsList = new LinkedList<DsResp>(); for (DS ds : rrd.getDsList()) dsList.add( new DsResp(ds.getName(), ds.getDst().toString(), ds.getHeartbeat(), ds.getMin(), ds.getMax()) ); LinkedList<RraResp> rraList = new LinkedList<RraResp>(); for (RRA rra : rrd.getRraList()) rraList.add( new RraResp( rra.getCf().getType(), rra.getPdpPerRow(), rra.getCf().getCfArguments().getRows(), rra.getCf().getCfArguments().getXff())Paolo Vanacore 566/1539 Pagina 160 di 279
    • ); RrdResp response = new RrdResp(rrdPathname, rrd.getVersion(), rrd.getStep(), rrd.getLastupdate(), dsList, rraList); oos.writeObject(response); } @Override public void sendResponse(ObjectOutputStream oos, List<MonitorThread> monitorThreadList) throws IOException,ParserConfigurationException, SAXException, ClassNotFoundException, SQLException { throw new IOException("unsupported method (use: " + "sendResponse(ObjectOutputStream oos))"); }}package it.unina.scope.wistat.dataclient.net;import java.util.LinkedList;public class RrdResp implements Response { private static final long serialVersionUID = -2400063055038054156L; private String rrdPathname = null; private String rrdVersion = null; private int rrdStep; private int rrdLastupdate; private LinkedList<DsResp> dsList = null; private LinkedList<RraResp> rraList = null; public RrdResp(String rrdPathname, String rrdVersion, int rrdStep, int rrdLastupdate, LinkedList<DsResp> dsList, LinkedList<RraResp> rraList){ this.rrdPathname = rrdPathname; this.rrdVersion = rrdVersion; this.rrdStep = rrdStep; this.rrdLastupdate = rrdLastupdate; this.dsList = dsList; this.rraList = rraList; } public String getRrdPathname(){ return rrdPathname; } public String getRrdVersion(){ return rrdVersion; } public int getRrdStep(){ return rrdStep; } public int getRrdLastupdate(){ return rrdLastupdate; } public LinkedList<DsResp> getDsList(){ return dsList; } public LinkedList<RraResp> getRraList(){ return rraList; }}package it.unina.scope.wistat.dataclient.net;import java.io.Serializable;public class Server implements Serializable { private static final long serialVersionUID = 3703853210474285773L; private String serverAddr = null; private int serverPort = 0; public Server(String serverAddr, int serverPort){ this.serverAddr = serverAddr; this.serverPort = serverPort; } public String getServerAddr(){ return serverAddr; }Paolo Vanacore 566/1539 Pagina 161 di 279
    • public int getServerPort(){ return serverPort; }}package it.unina.scope.wistat.dataclient.net;public class SuccessResponse implements Response { private static final long serialVersionUID = -8200842990859217626L;} 7.4.4 it.unina.scope.wistat.dataclient.rrdpackage it.unina.scope.wistat.dataclient.rrd;public class Absolute implements DSTInterface{ private static final String description = "ABSOLUTE"; public String toString(){ return(description); }}package it.unina.scope.wistat.dataclient.rrd;public class Average extends CF{ public Average(CFArguments cfArguments){ super(cfArguments); } public String getType(){ return "AVERAGE"; } public String toString(){ return ("CF: AVERAGE " + cfArguments); }}package it.unina.scope.wistat.dataclient.rrd;public abstract class CF{ CFArguments cfArguments = null; public CF(CFArguments cfArguments){ this.cfArguments = cfArguments; } void setCFArguments(CFArguments cfArguments){ this.cfArguments = cfArguments; } public String getType(){ return null; } public CFArguments getCfArguments(){ return cfArguments; }}package it.unina.scope.wistat.dataclient.rrd;public class CFArguments { private Double xff = null; private int rows = 0; public CFArguments(Double xff, int rows){ this.xff = xff; this.rows = rows; } void setXff(Double xff){ this.xff = xff; } void setRows(int rows){ this.rows = rows; } public Double getXff(){return xff; } public int getRows(){ return rows; } public String toString(){ return ("xff: " + xff.toString() + " rows: " + rows); }Paolo Vanacore 566/1539 Pagina 162 di 279
    • }package it.unina.scope.wistat.dataclient.rrd;public class Counter implements DSTInterface{ private static final String description = "COUNTER"; public String toString(){ return(description); }}package it.unina.scope.wistat.dataclient.rrd;public class Derive implements DSTInterface{ private static final String description = "DERIVE"; public String toString(){ return(description); }}package it.unina.scope.wistat.dataclient.rrd;public class DS { private String name = null; private Integer heartbeat = null; private Double min = null; private Double max = null; private DSTInterface dst = null; public DS(String name, Integer heartbeat, Double min, Double max, DSTInterface dst){ this.name = name; this.heartbeat = heartbeat; this.min = min; this.max = max; this.dst = dst; } void setName(String name){ this.name = name; } void setHeartbeat(Integer heartbeat){ this.heartbeat = heartbeat; } void setMin(Double min){ this.min = min; } void setMax(Double max){ this.max = max; } void setDst(DSTInterface dst){ this.dst = dst; } public String getName(){ return name; } public Integer getHeartbeat(){ return heartbeat; } public Double getMin(){ return min; } public Double getMax(){ return max; } public DSTInterface getDst(){ return dst; } public String toString(){ return( "Name: " + name + " heartbeat: " + heartbeat + " [min, max]: [" + min + ", " + max +"]" + " DataSourceType: " + dst ); }}package it.unina.scope.wistat.dataclient.rrd;public interface DSTInterface { public String toString();}Paolo Vanacore 566/1539 Pagina 163 di 279
    • package it.unina.scope.wistat.dataclient.rrd;public class Gauge implements DSTInterface{ private static final String description = "GAUGE"; public String toString(){ return(description); }}package it.unina.scope.wistat.dataclient.rrd;public class Last extends CF{ public Last(CFArguments cfArguments){super(cfArguments);} public String getType(){return "LAST";} public String toString(){return ("LAST " + cfArguments);}}package it.unina.scope.wistat.dataclient.rrd;public class Max extends CF{ public Max(CFArguments cfArguments){ super(cfArguments); } public String getType(){ return "MAX"; } public String toString(){ return ("MAX " + cfArguments); }}package it.unina.scope.wistat.dataclient.rrd;public class Min extends CF{ public Min(CFArguments cfArguments){ super(cfArguments); } public String getType(){ return "MIN"; } public String toString(){ return ("MIN " + cfArguments); }}package it.unina.scope.wistat.dataclient.rrd;public class RRA { private CF cf = null; private int pdp_per_row = 0; public RRA(CF cf, int pdp_per_row){ this.cf = cf; this.pdp_per_row = pdp_per_row; } void setCf(CF cf){ this.cf = cf; } void setPdpPerRow(Integer pdp_per_row){ this.pdp_per_row = pdp_per_row; } public CF getCf(){ return cf; } public int getPdpPerRow(){ return pdp_per_row; } public String toString(){ return (cf.toString() + " pdp_per_row: " + pdp_per_row); } public String dbToString(){ return(cf.toString()); }}package it.unina.scope.wistat.dataclient.rrd; import java.util.*;public class RRD { private String version = null; private int step; private int lastupdate; private LinkedList<DS> dsList = null;Paolo Vanacore 566/1539 Pagina 164 di 279
    • private LinkedList<RRA> rraList = null; public RRD(String version, int step, int lastupdate, LinkedList<DS> dsList, LinkedList<RRA> rraList){ this.version = version; this.step = step; this.lastupdate = lastupdate; this.dsList = dsList; this.rraList = rraList; } void setVersion(String version){ this.version = version; } void setStep(int step){ this.step = step; } void setLastupdate(int lastupdate){ this.lastupdate = lastupdate; } void setDsList(LinkedList<DS> dsList){ this.dsList = dsList; } void setRraList(LinkedList<RRA> rraList){ this.rraList = rraList; } public String getVersion(){ return version; } public int getStep(){ return step; } public int getLastupdate(){ return lastupdate; } public LinkedList<DS> getDsList(){ return dsList; } public LinkedList<RRA> getRraList(){ return rraList; } public String toString(){ return ("RRD:nt" + "version: " + version + "nt" + "step: " + step + "nt" + "last up: " + lastupdate + "n" + "DS: n" + dsList + "n" + "RRAs: n" + rraList + "n"); }}package it.unina.scope.wistat.dataclient.rrd;import java.util.EmptyStackException;import java.util.LinkedList;import java.util.Stack;import org.xml.sax.Attributes;import org.xml.sax.SAXParseException;import org.xml.sax.helpers.DefaultHandler;public class RRDAutomata extends DefaultHandler{ //Stack di servizio, per il parsing dellxml (cfr. getData()) private Stack<Object> lifo = null; private RRD rrd = null; //rrd da restituire in getData private int rowsCount = 0; //Contatore per le righe di ogni Database public RRDAutomata(){ lifo = new Stack<Object>(); //Stack per il parsing dellxml } public RRD getRrd(){ return rrd; } public void startElement(String namespaceURI, String localName, String element, Attributes attr){ Object objTmp = null; Object newObj = null; try{ objTmp = lifo.pop(); } catch (EmptyStackException ex){} if ( (element.equals("rrd")) && (objTmp == null) ) newObj = new RRD(null, 0, 0, new LinkedList<DS>(), new LinkedList<RRA>());Paolo Vanacore 566/1539 Pagina 165 di 279
    • else if ( (element.equals("ds")) && (objTmp instanceof RRD) ) newObj = new DS(null, null, null, null, null); else if ( (element.equals("rra")) && (objTmp instanceof RRD) ) newObj = new RRA(null, 0); else if ( (element.equals("params")) && (objTmp instanceof RRA)) newObj = new CFArguments(null, 0); else if (element.equals("row")){ ++rowsCount; newObj = element; } else newObj = element; if (objTmp != null) lifo.push(objTmp); lifo.push(newObj); } public void characters(char[] ch, int start, int length) { //Assegna il valore letto ed elimina eventuali spazi bianchi String value = ( ( new String(ch, start, length) ).replace(" ", "") ); //Estrae dallo stack lelemento cui il valore si riferisce Object element = lifo.pop(); //Il valore si riferisce ad un attributo if (element instanceof String){ //Estrae dallo stack loggetto cui lattributo si riferisce Object objTmp = lifo.pop(); if (objTmp instanceof RRD){ //Lattributo è di un RRD, in base al tipo di valore aggiorna lRRD RRD rrdTmp = (RRD) objTmp; if (element.equals("version")) rrdTmp.setVersion(value); else if (element.equals("step")) rrdTmp.setStep(Integer.parseInt(value)); else if (element.equals("lastupdate")) rrdTmp.setLastupdate(Integer.parseInt(value)); } else if (objTmp instanceof DS){ //Lattributo è di un DS, in base al tipo di valore aggiorna il DS DS dsTmp = (DS) objTmp; if (element.equals("name")) dsTmp.setName(value); else if (element.equals("type")){ DSTInterface dstTmp = null; if (value.equals("GAUGE")) dstTmp = new Gauge(); else if (value.equals("COUNTER")) dstTmp = new Counter(); else if (value.equals("DERIVE")) dstTmp = new Derive(); else if (value.equals("ABSOLUTE")) dstTmp = new Absolute(); dsTmp.setDst(dstTmp);Paolo Vanacore 566/1539 Pagina 166 di 279
    • } else if (element.equals("minimal_heartbeat")) dsTmp.setHeartbeat(Integer.parseInt(value)); else if (element.equals("min")) dsTmp.setMin(Double.parseDouble(value.replace(",", "."))); else if (element.equals("max")) dsTmp.setMax(Double.parseDouble(value.replace(",", "."))); } else if (objTmp instanceof RRA){ //Lattributo è di un RRA, in base al tipo di valore aggiorna il RRA RRA rraTmp = (RRA) objTmp; if (element.equals("cf")){ CF cfTmp = null; if (value.equals("AVERAGE")) cfTmp = new Average(null); else if (value.equals("MIN")) cfTmp = new Min(null); else if (value.equals("MAX")) cfTmp = new Max(null); else if (value.equals("LAST")) cfTmp = new Last(null); rraTmp.setCf(cfTmp); } else if (element.equals("pdp_per_row")) rraTmp.setPdpPerRow(Integer.parseInt(value)); } else if (objTmp instanceof CFArguments){ //Lattributo è di un CFArguments, in base al tipo aggiorna il CFArguments CFArguments cfarg = (CFArguments) objTmp; if (element.equals("xff")) cfarg.setXff(Double.parseDouble(value.replace(",", "."))); } lifo.push(objTmp); } lifo.push(element); } public void endElement(String namespaceURI, String localName,String element){ Object tmpObj = lifo.pop(); if ( (element == "rrd") && (tmpObj instanceof RRD) ) rrd = (RRD) tmpObj; else if ( (element == "ds") && (tmpObj instanceof DS) ){ Object rrdTmp = lifo.pop(); if (rrdTmp instanceof RRD) ((RRD) rrdTmp).getDsList().add((DS)tmpObj); lifo.push(rrdTmp); } else if ( (element == "rra") && (tmpObj instanceof RRA) ){ Object rrdTmp = lifo.pop(); ((RRA) tmpObj).getCf().getCfArguments().setRows(rowsCount); rowsCount = 0; if (rrdTmp instanceof RRD) ((RRD) rrdTmp).getRraList().add((RRA)tmpObj);Paolo Vanacore 566/1539 Pagina 167 di 279
    • lifo.push(rrdTmp); } else if ( (element == "params")&&(tmpObj instanceof CFArguments) ){ Object rraTmp = lifo.pop(); if (rraTmp instanceof RRA) ((RRA) rraTmp).getCf().setCFArguments((CFArguments)tmpObj); lifo.push(rraTmp); } } public void warning(SAXParseException ex){} public void error(SAXParseException ex){} public void fatalError(SAXParseException ex){}}package it.unina.scope.wistat.dataclient.stat;import java.util.LinkedList;public class DeviazioneStdCamp extends Function { private static final String type = "DeviazioneStdCamp"; public DeviazioneStdCamp(){} @Override public LinkedList<Double> compute(LinkedList<Double> valueList) { if (valueList == null) return null; LinkedList<Double> varList = (new VarianzaCamp()).compute(valueList); Double var = varList.get(0); LinkedList<Double> devList = new LinkedList<Double>(); devList.add(Math.sqrt(var)); return devList; } @Override public String getFunctionType() { return type; }}package it.unina.scope.wistat.dataclient.stat;import java.util.LinkedList;public abstract class Function { public abstract LinkedList<Double> compute(LinkedList<Double> valueList); public abstract String getFunctionType(); public static Function getInstance(String statFunction) throws Exception{ if (statFunction.equals("MediaCamp")) return new MediaCamp(); if (statFunction.equals("VarianzaCamp")) return new VarianzaCamp(); if (statFunction.equals("DeviazioneStdCamp")) return new DeviazioneStdCamp(); if (statFunction.equals("MedianaCamp")) return new MedianaCamp(); if (statFunction.equals("Min")) return new Min(); if (statFunction.equals("Max")) return new Max(); throw new Exception("no " + statFunction + " Function available"); } public static LinkedList<String> getFunctionsList(){ LinkedList<String> functionsList = new LinkedList<String>(); functionsList.add("MediaCamp"); functionsList.add("VarianzaCamp"); functionsList.add("DeviazioneStdCamp"); functionsList.add("MedianaCamp"); functionsList.add("Min"); functionsList.add("Max"); return functionsList;Paolo Vanacore 566/1539 Pagina 168 di 279
    • }}package it.unina.scope.wistat.dataclient.stat;import java.util.LinkedList;public class Max extends Function{ private static final String type = "Max"; public Max(){} @Override public LinkedList<Double> compute(LinkedList<Double> valueList) { if (valueList == null) return null; Double max = null; for(Double value : valueList) if (max == null || value > max) max = value; LinkedList<Double> maxList = new LinkedList<Double>(); maxList.add(max); return maxList; } @Override public String getFunctionType() {return type;}}package it.unina.scope.wistat.dataclient.stat;import java.util.LinkedList;public class MediaCamp extends Function { private final String type = "MediaCamp"; public MediaCamp(){} @Override public LinkedList<Double> compute(LinkedList<Double> valueList) { Double average = new Double(0); for (Double data : valueList) average += data; LinkedList<Double> resultList = new LinkedList<Double>(); resultList.add(average/valueList.size()); return resultList; } @Override public String getFunctionType() { return type; }}package it.unina.scope.wistat.dataclient.stat;import java.util.Collections;import java.util.LinkedList;public class MedianaCamp extends Function { private static final String type = "MedianaCamp"; public MedianaCamp(){} @Override public LinkedList<Double> compute(LinkedList<Double> valueList) { if (valueList == null) return null; int n = valueList.size(); Collections.sort(valueList); Double mediana = null; if ((n % 2) == 0) mediana = (valueList.get(n/2 -1) + valueList.get(n/2))/2; else mediana = valueList.get(n/2);Paolo Vanacore 566/1539 Pagina 169 di 279
    • LinkedList<Double> medianaList = new LinkedList<Double>(); medianaList.add(mediana); return medianaList; } @Override public String getFunctionType() { return type; }}package it.unina.scope.wistat.dataclient.stat;import java.util.LinkedList;public class Min extends Function { private static final String type = "Min"; public Min(){} @Override public LinkedList<Double> compute(LinkedList<Double> valueList) { if (valueList == null) return null; Double min = null; for(Double value : valueList) if (min == null || value < min) min = value; LinkedList<Double> minList = new LinkedList<Double>(); minList.add(min); return minList; } @Override public String getFunctionType() {return type;}}package it.unina.scope.wistat.dataclient.stat;import java.util.LinkedList;public class VarianzaCamp extends Function { private static final String type = "VarianzaCamp"; public VarianzaCamp(){} @Override public LinkedList<Double> compute(LinkedList<Double> valueList) { Double average = (new MediaCamp().compute(valueList)).get(0); if (average == null) return null; Double n = new Double(valueList.size()); Double sum = new Double(0); for (Double x : valueList) sum += ( Math.pow((x - average), 2) ); Double var = (1/(n-1))*sum; LinkedList<Double> varList = new LinkedList<Double>(); varList.add(var); return varList; } @Override public String getFunctionType() {return type;}} 7.4.5 Files di configurazione DataClient dataclient_config.xmlPaolo Vanacore 566/1539 Pagina 170 di 279
    • <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE configuration SYSTEM "dataclient_config.dtd"><!-- Configuration file for DumperServer --><configuration> <!-- Parametri socket per servizi di amministrazione --> <serviceSocket> <!-- Porta socket per servizi di amministrazione --> <port>61001</port> </serviceSocket> <!-- Parametri per laccesso al db per i dati degli rrd --> <rrdb> <!-- Nome del db per i dati degli rrd --> <dbName>rrdb</dbName> <!-- Nome utente per laccesso al db di cacti --> <userName>RrdbUserName</userName> <!-- Password per laccesso al db di cacti --> <userPwd>RrdbUserPass</userPwd> </rrdb></configuration> dataclient_config.dtd<!ELEMENT configuration (serviceSocket, rrdb)><!ELEMENT serviceSocket (port)><!ELEMENT port (#PCDATA)><!ELEMENT rrdb (dbName, userName, userPwd)><!ELEMENT dbName (#PCDATA)><!ELEMENT userName (#PCDATA)><!ELEMENT userPwd (#PCDATA)> 7.4.6 it.unina.scope.wistat.dataserverpackage it.unina.scope.wistat.dataserver;import it.unina.scope.wistat.dataserver.net.ErrorResponse;import it.unina.scope.wistat.dataserver.net.Request;import java.net.*;import java.io.*;import java.text.SimpleDateFormat;import java.util.*;public class ClientManager implements Runnable{ private Socket incoming; //Socket dedicato al client public ClientManager(Socket incoming){ this.incoming = incoming; } private void log(String toLog){ String time = null; //Stringa per la data ed ora corrente Calendar calendar = Calendar.getInstance(); //Oggetto calendario SimpleDateFormat simpleDataFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //Formato dataPaolo Vanacore 566/1539 Pagina 171 di 279
    • //Restituisce data e ora corrente secondo il formato simpleDateFormat time = simpleDataFormat.format(calendar.getTime()); System.out.println(time + "::" + toLog); //Mostra sullo stdout } public void run(){ ObjectInputStream ois = null; //Stream lettura oggetti generici ObjectOutputStream oos = null; //Stream scrittura oggetti generici try{ //Inizializzazione ambiente per la comunicazione con il client //Stream di ingresso per leggere oggetti generici ois = new ObjectInputStream(incoming.getInputStream()); //Stream di uscita per scrivere oggetti generici oos = new ObjectOutputStream(incoming.getOutputStream()); Request request = null; //Rappresenta una richiesta del client request = (Request) ois.readObject(); //Riceve richiesta client log("Client request::" + incoming.getInetAddress() + ":" + incoming.getPort() + ":" + request); //Log info try { request.sendResponse(oos); //Invia la risposta } catch (Exception ex){ //Log info log("Server activity::" + incoming.getInetAddress()+":" + incoming.getPort() + "::Exception::" + ex.toString()); log("Server activity::sending Unknown request to " + incoming.getInetAddress() + ":" + incoming.getPort()); oos.writeObject(new ErrorResponse(ex.getMessage())); } ois.close(); //Chiusura stream di input associato alla socket oos.close(); //Chiusura stream di output associato alla socket incoming.close(); //Chiude la socket } catch (Exception ex){ log("Server activity::error status with " + incoming.getInetAddress() + ":" + incoming.getPort() + "::Details: " + ex);//Log info } }}package it.unina.scope.wistat.dataserver;import java.net.*;import java.util.*;import java.text.*;public class DataServer{ public static void main(String[] args){ new DataServer().startServer(); } private void log(String toLog){ String time = null; //Stringa per data e ora corrente per info //Calendario data ora corrente Calendar calendar = Calendar.getInstance(); //Definisce formato della data ed ora desiderati SimpleDateFormat simpleDataFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //Inizializza la data e lora corrente secondo il formato impostato time = simpleDataFormat.format(calendar.getTime()); //Scrive su stdout ora e data corrente seguiti dal parametro toLog System.out.println(time + "::" + toLog); } private void startServer(){ ServerConfiguration config = ServerConfiguration.getInstance();Paolo Vanacore 566/1539 Pagina 172 di 279
    • int serverPort = config.getServerPort(); try { //Socket in attesa di richieste di connessione ServerSocket serverSocket = new ServerSocket(serverPort); log("Server start:: " + config.getConfiguration()); //Log info while(true){ //Ciclo infinito //Alloccorrenza di richiesta connessione, crea socket dedicata Socket incoming = serverSocket.accept(); //Costruisce oggetto per la gestione della connessione con il client Runnable clientManager = new ClientManager(incoming); //Crea un thread per la gestione della connessione con il client Thread clientManagerThread = new Thread(clientManager); clientManagerThread.start(); //Avvia il thread } } catch (Exception ex) { ex.printStackTrace(); } }}package it.unina.scope.wistat.dataserver;import java.io.File;import org.w3c.dom.*;import org.xml.sax.ErrorHandler;import org.xml.sax.SAXException;import org.xml.sax.SAXParseException;import javax.xml.parsers.*;import javax.xml.xpath.*;public class ServerConfiguration implements ErrorHandler{ private String configPath = null; //Pathname file xml di configurazione private int serverPort = 0; //Porta sulla quale mettersi in ascolto private String rrdtoolPath = null; //Pathname al binario di RRDTool //Cartella dove memorizzare, temporaneamente, i file di dump xml private String xmlPath = null; private String cactiDbName = null; private String cactiDbUserName = null; private String cactiDbUserPwd = null; //Unica istanza della classe ServerConfiguration private static final ServerConfiguration singleton=new ServerConfiguration(); private ServerConfiguration(){ File f = new File (System.getProperty ("java.class.path")); File dir = f.getAbsoluteFile ().getParentFile (); xmlPath = dir.getAbsolutePath()+"/xml/"; configPath = dir.getAbsolutePath()+"/server_config.xml"; //Factory per il file di configurazione xml DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); //Abilitazione del namespace factory.setValidating(true); //Abilitazione validazione new File(xmlPath).mkdir(); try{ //Builder per il file di configurazione xml DocumentBuilder builder = factory.newDocumentBuilder(); builder.setErrorHandler(this); //Handler per errori di parsing //Parsing del file xml di configurazione Document doc = builder.parse(configPath); //XPath factory per il file di configurazione xml XPathFactory xpfactory = XPathFactory.newInstance(); //Nuovo xpath per valutare le espressioni XPathPaolo Vanacore 566/1539 Pagina 173 di 279
    • XPath xpath = xpfactory.newXPath(); //Lettura numero porta di ascolto del server serverPort = Integer.parseInt( xpath.evaluate("/configuration/serverPort", doc)); //Lettura pathname al binario di RRDTool rrdtoolPath = xpath.evaluate("/configuration/rrdtoolPath", doc); //Lettura nome database di cacti cactiDbName = xpath.evaluate("/configuration/cactiDb/dbName", doc); //Lettura nome utente database cacti cactiDbUserName=xpath.evaluate("/configuration/cactiDb/userName",doc); //Lettura password utente database cacti cactiDbUserPwd=xpath.evaluate("/configuration/cactiDb/userPwd",doc); } catch(Exception ex){ rrdtoolPath = null; serverPort = 0; ex.printStackTrace(); } } public static ServerConfiguration getInstance(){ if ((singleton.getServerPort() == 0) || (singleton.getRrdtoolPath() == null)) return null; else return singleton; } public String getConfiguration(){ StringBuffer dbUserPass = new StringBuffer(); int dbUserPassLength = cactiDbUserPwd.length(); for (int i = 0; i < dbUserPassLength; ++i) dbUserPass.append("*"); return new String ( "listening port: [" + serverPort + "] " + ":: rrdtoolPath: [" + rrdtoolPath + "] " + ":: xmlPath: [" + xmlPath + "] " + ":: cactiDbName: [" + cactiDbName + "] "+ ":: cactiDbUserName: ["+ cactiDbUserName + "] "+ ":: cactiDbUserPwd: ["+ dbUserPass+ "] " ); } public String getConfigPath(){ return configPath; } public int getServerPort(){ return serverPort; } public String getRrdtoolPath(){ return rrdtoolPath; } public String getXmlPath(){ return xmlPath; } public String getCactiDbName(){return cactiDbName; } public String getCactiDbUserName(){ return cactiDbUserName; } public String getCactiDbUserPwd(){ return cactiDbUserPwd; } public void error(SAXParseException ex) throws SAXException { rrdtoolPath = null; serverPort = 0; ex.printStackTrace(); } public void fatalError(SAXParseException ex) throws SAXException { rrdtoolPath = null; serverPort = 0; ex.printStackTrace(); } public void warning(SAXParseException ex) throws SAXException { rrdtoolPath = null; serverPort = 0; ex.printStackTrace(); }}Paolo Vanacore 566/1539 Pagina 174 di 279
    • 7.4.7 it.unina.scope.wistat.dataserver.databasepackage it.unina.scope.wistat.dataserver.database;import java.sql.*;import java.util.Vector;public class MysqlDatabase { private String dbName = null; //Nome del Database private String userName = null; //Nome utente per Database private String userPwd = null; //Password utente Database private String error = null; //Contiene info su eventuali errori private Connection db = null; //Connessione al Database //Indica lo stato della connessione (true: connesso; false: non connesso) private boolean connStatus; public MysqlDatabase (String dbName, String userName, String userPwd){ this.dbName = dbName; this.userName = userName; this.userPwd = userPwd; connStatus = false; } public boolean connect(){ connStatus = false; try { //Carica driver JDBC Class.forName("com.mysql.jdbc.Driver"); //Effettua la connessione db=DriverManager.getConnection("jdbc:mysql://localhost/"+ dbName + "?user=" + userName + "&password=" + userPwd); //Connessione effettuata connStatus = true; } catch (Exception ex) { error = ex.getMessage(); } return connStatus; } public Vector<String[]> query(String query) { Vector<String[]> result = null; String [] record; int colums = 0; try { //Statement per lesecuzione della query Statement statement = db.createStatement(); //ResultSet dellesecuzione della query ResultSet resultSet = statement.executeQuery(query); result = new Vector<String[]>(); //Vettore per i risultati //ResultSetMetaData del risultato della query ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); //Numero di colonne del risultato della query colums = resultSetMetaData.getColumnCount(); //Scorre il ResultSet e crea il vettore risultato while(resultSet.next()){ record = new String[colums]; for (int i=0; i<colums; i++) record[i] = resultSet.getString(i+1); result.add( (String[])record.clone() ); } resultSet.close(); //Chiusura ResultSetPaolo Vanacore 566/1539 Pagina 175 di 279
    • statement.close(); //Chiusura Statement } catch (Exception ex) { //In caso di eccezione... error = ex.getMessage(); //salva in error leccezione } return result; } public void disconnect() { try { db.close(); connStatus = false; } catch (Exception e){ e.printStackTrace(); } } public boolean getConnectionStatus() { return connStatus; } public String getError(){ return error; }} 7.4.8 it.unina.scope.wistat.dataserver.netpackage it.unina.scope.wistat.dataserver.net;import it.unina.scope.wistat.dataserver.ServerConfiguration;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.ObjectOutputStream;import java.util.LinkedList;import java.util.StringTokenizer;import java.util.Vector;public class DataRequest implements Request{ private static final long serialVersionUID = 387811900486083255L; private String rrdPath = null; private String dsId = null; private String cfName = null; private int resolution = 0; private int startTime = 0; public DataRequest(String rrdPath, String dsId, String cfName, int resolution, int startTime){ this.rrdPath = rrdPath; this.dsId = dsId; this.cfName = cfName; this.resolution = resolution; this.startTime = startTime; } public String getRrdPath(){ return rrdPath; } public String getDsId(){ return dsId; } public String getCfName(){ return cfName; } public int getResolution(){ return resolution; } public int getStartTime(){ return startTime; } public void sendResponse(ObjectOutputStream oos) throws IOException { Process rrdTool = null; //Processo per lesecuzione di RRDTool String tmpStr = null; //Stringa lettura degli output di RRDTool //Stringa tokanizzata per lettura output di RRDTool StringTokenizer tmpStrTok = null; BufferedReader stdout = null; //Standard out di RRDTool BufferedReader stderr = null; //Standard error di RRDTool LinkedList<Vector<String>> numberList = null; //Lista per rispostaPaolo Vanacore 566/1539 Pagina 176 di 279
    • Vector<String> valueVector = null; //Valore per la lista //Comando per lesecuzione del fetch tramite RRDTool String[] rrdtoolCommand = null; int dsIndex = 0; //Indice numerico del data source //Parametri da passare a RRDTool if (startTime != 0) rrdtoolCommand = new String[]{ ServerConfiguration.getInstance().getRrdtoolPath(), "fetch", rrdPath, cfName, "-r", Integer.toString(resolution), "-s", Integer.toString(startTime)}; else rrdtoolCommand = new String[]{ ServerConfiguration.getInstance().getRrdtoolPath(), "fetch",rrdPath,cfName,"-r", Integer.toString(resolution),}; //Fase di fetch //Esecuzione processo RRDTool rrdTool = Runtime.getRuntime().exec(rrdtoolCommand); stdout = new BufferedReader(new InputStreamReader( rrdTool.getInputStream())); //Stdout //Lista per la risposta numberList = new LinkedList<Vector<String>>(); //Lettura intestazione e calcolo id del ds dsIndex = 0; tmpStr = stdout.readLine(); tmpStrTok = new StringTokenizer(tmpStr); try { for (String cursor = tmpStrTok.nextToken(); tmpStrTok != null;) if (cursor.compareTo(dsId)!=0){ ++dsIndex; cursor = tmpStrTok.nextToken(); } else tmpStrTok = null; } catch(Exception ex){ throw new IOException("DS " + dsId + " not found!"); } //Lettura riga vuota tmpStr = stdout.readLine(); //Inizio lettura valori for(tmpStr=stdout.readLine();tmpStr!=null;tmpStr = stdout.readLine()){ //Tocanizza la stringa tmpStrTok = new StringTokenizer(tmpStr, ":" + " " + "t"); valueVector = new Vector<String>(2); valueVector.add(0, tmpStrTok.nextToken()); //Add valore data //Posizionamento cursore sul valore del ds desiderato for (int i = 0; i < dsIndex; ++i) tmpStrTok.nextToken(); valueVector.add(1, tmpStrTok.nextToken()); numberList.add(valueVector); } stdout.close(); //Chiusura stdout rrdtool stderr = new BufferedReader(new InputStreamReader( rrdTool.getErrorStream())); //Stderror tmpStr = stderr.readLine(); if(tmpStr!=null){ tmpStr = tmpStr+"n"; tmpStr = stderr.readLine(); while(tmpStr!=null){Paolo Vanacore 566/1539 Pagina 177 di 279
    • tmpStr += tmpStr+"n"; tmpStr = stderr.readLine(); } stderr.close(); throw new IOException(tmpStr); } stderr.close(); oos.writeObject(new DataResponse(numberList)); } public String toString(){ return ("data request: " + "[rrd: " + rrdPath + "] " + "[dsId: " + dsId + "] " + "[cfName: " + cfName + "] " + "[resolution: " + resolution + "] " + "[start time: " + startTime + "] "); }}package it.unina.scope.wistat.dataserver.net;import java.util.LinkedList;import java.util.Vector;public class DataResponse implements Response{ private static final long serialVersionUID = 1033735879358577634L; private LinkedList<Vector<String>> numberList = null; public DataResponse(LinkedList<Vector<String>> numberList){ this.numberList = numberList; } public LinkedList<Vector<String>> getNumberList(){ return numberList; } public String toString(){ return (numberList.toString()); }}package it.unina.scope.wistat.dataserver.net;import it.unina.scope.wistat.dataserver.ServerConfiguration;import java.io.BufferedReader;import java.io.File;import java.io.InputStream;import java.io.InputStreamReader;public class Dumper { private String rrdPath = null; private String xmlPath = null; public Dumper(String rrdPath, String xmlPath){ this.rrdPath = rrdPath; this.xmlPath = xmlPath; } public String getRrdPath(){ return rrdPath; } public String getXmlPath(){ return xmlPath; } public void setRrdPath(String rrdPath){ this.rrdPath = rrdPath; } public void setXmlPath(String xmlPath){ this.xmlPath = xmlPath; } public String doDump(){ Process rrdTool = null; //Processo per lesecuzione di RRDTool //StringBuffer contenente informazioni sul processo di dump StringBuffer log = null; ServerConfiguration config = ServerConfiguration.getInstance(); //Parametri da passare a RRDTool String[] rrdtoolCommand={config.getRrdtoolPath(), "dump", rrdPath,xmlPath};Paolo Vanacore 566/1539 Pagina 178 di 279
    • //Dichiarazione ambiente per la lettura di eventuali errori di rrdTool //Stream di input per la lettura dello stderr di RRDTool InputStream rrdtoolInputStream = null; //StreamReader per la lettura dello stderr di RRDTool InputStreamReader rrdtoolInputStreamReader = null; //BufferedReader per la lettura dello stderr di RRDTool BufferedReader rrdtoolBufferedReader = null; //String per la memorizzazione di eventuali messaggi derrore di RRDTool String rrdtoolErrorString = null; //Dump del file rrd in xml tramite esecuzione di un processo rrdTool try { //Esecuzione processo RRDTool rrdTool = Runtime.getRuntime().exec(rrdtoolCommand); //Inizializzazione ambiente per la lettura dello stderr di rrdTool //Inizializzazione stream di input rrdtoolInputStream = rrdTool.getErrorStream(); //Inizializzazione stream reader rrdtoolInputStreamReader = new InputStreamReader(rrdtoolInputStream); //Inizializzazione buffered reader rrdtoolBufferedReader = new BufferedReader(rrdtoolInputStreamReader); //In attesa della fine del processo di conversione rrdTool.waitFor(); //Attesa della fine del processo RRDTool //Salvataggio eventuali errori di rrdTool nella stringa di log if ((rrdtoolErrorString = rrdtoolBufferedReader.readLine()) != null) log = new StringBuffer(rrdtoolErrorString); while((rrdtoolErrorString = rrdtoolBufferedReader.readLine()) != null) log.append(rrdtoolErrorString); //Lettura stderr di RRDTool } catch (Exception ex){ //Cattura eventuali eccezioni del processo di dump log.append(ex.toString()); //Log info (new File(xmlPath)).delete(); //Elimina il file xml } if (log == null) return null; else return(log.toString()); }}package it.unina.scope.wistat.dataserver.net;public class ErrorResponse implements Response{ private static final long serialVersionUID = -9008922901261668306L; private String errorDetails = null; public ErrorResponse(){} public ErrorResponse(String errorDetails){ this.errorDetails=errorDetails;} public void setErrorDetails(String errorDetails){ this.errorDetails = errorDetails; } public String getErrorDetails(){ return errorDetails; } public String toString(){ return errorDetails; }}package it.unina.scope.wistat.dataserver.net;import it.unina.scope.wistat.dataserver.ServerConfiguration;import it.unina.scope.wistat.dataserver.database.MysqlDatabase;import java.io.IOException;import java.io.ObjectOutputStream;Paolo Vanacore 566/1539 Pagina 179 di 279
    • import java.util.LinkedList;import java.util.Vector;public class HostListRequest implements Request{ private static final long serialVersionUID = -5562824734956423125L; public void sendResponse(ObjectOutputStream oos) throws IOException{ LinkedList<HostResponse>hostLinkedList=new LinkedList<HostResponse>(); ServerConfiguration config = ServerConfiguration.getInstance(); MysqlDatabase db = new MysqlDatabase(config.getCactiDbName(), config.getCactiDbUserName(), config.getCactiDbUserPwd()); if (! db.connect()){ oos.writeObject(new ErrorResponse("db error")); throw new IOException(db.getError()); } else { String [] record = null; String query = null; query = "SELECT DISTINCT description, hostname FROM host;"; Vector<String[]> v = db.query(query); db.disconnect(); for (int i = 0; i < v.size(); ++i){ record = (String[]) v.elementAt(i); hostLinkedList.add(new HostResponse(null,record[0],record[1])); } } oos.writeObject(new HostListResponse(hostLinkedList)); } public String toString(){ return ("host list request "); }}package it.unina.scope.wistat.dataserver.net;import java.util.LinkedList;public class HostListResponse implements Response{ private static final long serialVersionUID = -791272404918202715L; private LinkedList<HostResponse> hostList = null; public HostListResponse(){} public HostListResponse(LinkedList<HostResponse> hostList){ this.hostList = hostList; } public void setHostList(LinkedList<HostResponse> hostList){ this.hostList = hostList; } public LinkedList<HostResponse> getHostList(){ return hostList; } public String toString(){ return (hostList.toString()); }}package it.unina.scope.wistat.dataserver.net;import it.unina.scope.wistat.dataserver.ServerConfiguration;import it.unina.scope.wistat.dataserver.database.MysqlDatabase;import java.io.IOException;import java.io.ObjectOutputStream;import java.util.LinkedList;import java.util.Vector;public class HostRequest implements Request{ private static final long serialVersionUID = 3732423701860556785L; private String hostname = null; public HostRequest(String hostname){ this.hostname = hostname; }Paolo Vanacore 566/1539 Pagina 180 di 279
    • public void setHostname(String hostname){ this.hostname = hostname; } public String getHostname(){ return hostname; } public void sendResponse(ObjectOutputStream oos) throws IOException{ ServerConfiguration config = ServerConfiguration.getInstance(); MysqlDatabase db = new MysqlDatabase(config.getCactiDbName(), config.getCactiDbUserName(), config.getCactiDbUserPwd()); if (! db.connect()){ oos.writeObject(new ErrorResponse("db error")); throw new IOException(db.getError()); } else { String [] record = null; String query = null; String description = null; LinkedList<RRDFileResponse> rrdFileList = null; query = "SELECT DISTINCT " + "h.hostname, h.description, p.rrd_path " + "FROM " + "host AS h " + "JOIN " +"poller_item AS p " + "ON " + "h.id = p.host_id " + "WHERE " + "h.hostname="" + hostname + "";"; Vector<String[]> v = db.query(query); db.disconnect(); try { description = v.elementAt(0)[1]; rrdFileList = new LinkedList<RRDFileResponse>(); for (int i = 0; i < v.size(); ++i){ record = (String[]) v.elementAt(i); rrdFileList.add(new RRDFileResponse(record[2])); } } catch(Exception ex){ oos.writeObject(new ErrorResponse("Unknown host: "+hostname)); throw new IOException("Unknown host: " + hostname); } oos.writeObject(new HostResponse(rrdFileList, description, hostname)); } } public String toString(){ return ("host request: " + hostname); }}package it.unina.scope.wistat.dataserver.net;import java.util.LinkedList;public class HostResponse implements Response{ private static final long serialVersionUID = 7001076384162597244L; //Lista dei files rrd associati allhost private LinkedList<RRDFileResponse> rrdFileList = null; private String description = null; //Descrizione dellhost private String hostname = null; //Hostname dellhost public HostResponse(String hostname){ this.hostname = hostname; } public HostResponse(LinkedList<RRDFileResponse> rrdFileList, String description, String hostname){ this.rrdFileList = rrdFileList; this.description = description; this.hostname = hostname;Paolo Vanacore 566/1539 Pagina 181 di 279
    • } public void setDescription(String description){ this.description = description; } public String getDescription(){ return description; } public void setHostname(String hostname){ this.hostname = hostname; } public String getHostname(){ return hostname; } public void setRrdFileList(LinkedList<RRDFileResponse> rrdFileList){ this.rrdFileList = rrdFileList; } public LinkedList<RRDFileResponse> getRrdFileList(){ return rrdFileList; } public void addRrd(RRDFileResponse rrd){ rrdFileList.add(rrd); } public String toString(){ return(hostname + " " + description + " " + rrdFileList); }}package it.unina.scope.wistat.dataserver.net;import java.io.IOException;import java.io.ObjectOutputStream;import java.io.Serializable;public interface Request extends Serializable{ public void sendResponse(ObjectOutputStream oos) throws IOException;}package it.unina.scope.wistat.dataserver.net;import java.io.Serializable;public interface Response extends Serializable {}package it.unina.scope.wistat.dataserver.net;public class RRDFileResponse implements Response{ private static final long serialVersionUID = -6620784168250746204L; private String rrdPath = null; //Pathname al file rrd public RRDFileResponse(){} public RRDFileResponse(String rrdPath){ this.rrdPath = rrdPath; } public void setRrdPath(String rrdPath){ this.rrdPath = rrdPath; } public String getRrdPath(){ return rrdPath; } public String toString(){ return rrdPath; }}package it.unina.scope.wistat.dataserver.net;public class SuccessResponse implements Response { private static final long serialVersionUID = 7749314502253328826L;}package it.unina.scope.wistat.dataserver.net;import it.unina.scope.wistat.dataserver.ServerConfiguration;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.ObjectOutputStream;public class XmlDumpFileRequest implements Request{ private static final long serialVersionUID = 8741002911064578420L;Paolo Vanacore 566/1539 Pagina 182 di 279
    • private String rrdPath = null; private String xmlPath = null; public XmlDumpFileRequest(String rrdPath, String xmlPath){ this.rrdPath = rrdPath; this.xmlPath = xmlPath; } public void setRrdPath(String rrdPath){ this.rrdPath = rrdPath; } public String getRrdPath(){ return rrdPath; } public void setXmlPath(String xmlPath){ this.xmlPath = xmlPath; } public String getXmlPath(){ return xmlPath; } public void sendResponse(ObjectOutputStream oos) throws IOException{ File xmlTmpFile = null; ServerConfiguration config = ServerConfiguration.getInstance(); try{ //File xml, temporaneo, dump del file rrd, da inviare al client xmlTmpFile = File.createTempFile("tmp", ".xml", new File(config.getXmlPath())); //Effettua il dump del file rrd in xml String conversionResponse = (new Dumper(rrdPath, xmlTmpFile.getPath())).doDump(); if (conversionResponse == null){ //Se non ci sono errori di conversione //Invia al client una risposta di successo delloperazione oos.writeObject(new SuccessResponse()); //Stream per la lettura del file xml FileInputStream fis = new FileInputStream(xmlTmpFile.getPath()); //Definizione pacchetto di byte da inviare rappresentante il file xml byte [] packet = new byte[fis.available()]; fis.read(packet); //Inizializzazione del pacchetto fis.close(); //Chiusura stream per lettura del file xml oos.writeObject(packet); //Invio pacchetto/file xml } else { //Se ci sono stati errori nel processo di conversione //Invia al client le informazioni circa lerrore occorso oos.writeObject(new ErrorResponse(conversionResponse)); throw new IOException(conversionResponse); } } finally { xmlTmpFile.delete(); //Elimina il file xml locale } } public String toString(){ return ("dump " + rrdPath); }} 7.4.9 Files di configurazione DataServer server_config.xml<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE configuration SYSTEM "server_config.dtd"><!-- Configuration file for DumperServer --><configuration> <!-- Listening port --> <serverPort>61000</serverPort> <!-- Pathname to RRDTool binary file -->Paolo Vanacore 566/1539 Pagina 183 di 279
    • <rrdtoolPath>/usr/bin/rrdtool</rrdtoolPath> <!-- Parametri per laccesso al db di cacti --> <cactiDb> <!-- Nome del db di cacti --> <dbName>cactiDBName</dbName> <!-- Nome utente per laccesso al db di cacti --> <userName>userNameCactiDB</userName> <!-- Password per laccesso al db di cacti --> <userPwd>userPasswordCactiDB</userPwd> </cactiDb></configuration> server_config.dtd<!ELEMENT configuration (serverPort, rrdtoolPath, cactiDb)><!ELEMENT serverPort (#PCDATA)><!ELEMENT rrdtoolPath (#PCDATA)><!ELEMENT cactiDb (dbName, userName, userPwd)><!ELEMENT dbName (#PCDATA)><!ELEMENT userName (#PCDATA)><!ELEMENT userPwd (#PCDATA)> 7.4.10 Script SQL per la creazione del database rrdbSET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE=TRADITIONAL;CREATE SCHEMA IF NOT EXISTS `rrdb` DEFAULT CHARACTER SET latin1 COLLATElatin1_swedish_ci ;USE `rrdb`;-- ------------------------------------------------------- Table `rrdb`.`SERVER`-- -----------------------------------------------------CREATE TABLE IF NOT EXISTS `rrdb`.`SERVER` ( `Server_Address` VARCHAR(500) NOT NULL , `Server_Port` INT NOT NULL , PRIMARY KEY (`Server_Address`, `Server_Port`) )ENGINE = InnoDB;-- ------------------------------------------------------- Table `rrdb`.`RRD`-- -----------------------------------------------------CREATE TABLE IF NOT EXISTS `rrdb`.`RRD` ( `Rrd_FilePathName` VARCHAR(500) NOT NULL , `Server_Address` VARCHAR(500) NOT NULL , `Server_Port` INT NOT NULL , `Version` VARCHAR(45) NOT NULL , `Step` INT NOT NULL , PRIMARY KEY (`Rrd_FilePathName`, `Server_Address`, `Server_Port`) , INDEX `fk_RRD_SERVER` (`Server_Address` ASC, `Server_Port` ASC) , CONSTRAINT `fk_RRD_SERVER` FOREIGN KEY (`Server_Address` , `Server_Port` )Paolo Vanacore 566/1539 Pagina 184 di 279
    • REFERENCES `rrdb`.`SERVER` (`Server_Address` , `Server_Port` ) ON DELETE CASCADE ON UPDATE CASCADE)ENGINE = InnoDB;-- ------------------------------------------------------- Table `rrdb`.`DS`-- -----------------------------------------------------CREATE TABLE IF NOT EXISTS `rrdb`.`DS` ( `Ds_Name` VARCHAR(500) NOT NULL , `Rrd_FilePathName` VARCHAR(500) NOT NULL , `Server_Address` VARCHAR(500) NOT NULL , `Server_Port` INT NOT NULL , `Type` VARCHAR(45) NOT NULL , `Heartbeat` INT NOT NULL , `Min` DOUBLE NOT NULL , `Max` DOUBLE NOT NULL , PRIMARY KEY (`Ds_Name`, `Rrd_FilePathName`, `Server_Address`, `Server_Port`) , INDEX `fk_DS_RRD1` (`Rrd_FilePathName` ASC, `Server_Address` ASC, `Server_Port`ASC) , CONSTRAINT `fk_DS_RRD1` FOREIGN KEY (`Rrd_FilePathName` , `Server_Address` , `Server_Port` ) REFERENCES `rrdb`.`RRD` (`Rrd_FilePathName` , `Server_Address` , `Server_Port`) ON DELETE CASCADE ON UPDATE CASCADE)ENGINE = InnoDB;-- ------------------------------------------------------- Table `rrdb`.`RRA`-- -----------------------------------------------------CREATE TABLE IF NOT EXISTS `rrdb`.`RRA` ( `Rra_CfName` VARCHAR(45) NOT NULL , `Rra_Resolution` INT NOT NULL , `Ds_Name` VARCHAR(500) NOT NULL , `Rrd_FilePathName` VARCHAR(500) NOT NULL , `Server_Address` VARCHAR(500) NOT NULL , `Server_Port` INT NOT NULL , `Rows` INT NOT NULL , `Description` VARCHAR(500) NULL , PRIMARY KEY (`Rra_CfName`, `Ds_Name`, `Rrd_FilePathName`, `Server_Address`,`Server_Port`, `Rra_Resolution`) , INDEX `fk_RRA_DS1` (`Ds_Name` ASC, `Rrd_FilePathName` ASC, `Server_Address` ASC,`Server_Port` ASC) , CONSTRAINT `fk_RRA_DS1` FOREIGN KEY (`Ds_Name` , `Rrd_FilePathName` , `Server_Address` , `Server_Port`) REFERENCES `rrdb`.`DS` (`Ds_Name` , `Rrd_FilePathName` , `Server_Address` ,`Server_Port` ) ON DELETE CASCADE ON UPDATE CASCADE)ENGINE = InnoDB;-- ------------------------------------------------------- Table `rrdb`.`DATA`-- -----------------------------------------------------CREATE TABLE IF NOT EXISTS `rrdb`.`DATA` ( `Data_Time` TIMESTAMP NOT NULL , `Rra_CfName` VARCHAR(45) NOT NULL , `Rra_Resolution` INT NOT NULL , `Ds_Name` VARCHAR(500) NOT NULL , `Rrd_FilePathName` VARCHAR(500) NOT NULL ,Paolo Vanacore 566/1539 Pagina 185 di 279
    • `Server_Address` VARCHAR(500) NOT NULL , `Server_Port` INT NOT NULL , `Value` DOUBLE NOT NULL , PRIMARY KEY (`Data_Time`, `Rra_CfName`, `Ds_Name`, `Rrd_FilePathName`,`Server_Address`, `Server_Port`, `Rra_Resolution`) , INDEX `fk_DATA_RRA1` (`Rra_CfName` ASC, `Ds_Name` ASC, `Rrd_FilePathName` ASC,`Server_Address` ASC, `Server_Port` ASC, `Rra_Resolution` ASC) , CONSTRAINT `fk_DATA_RRA1` FOREIGN KEY (`Rra_CfName` , `Ds_Name` , `Rrd_FilePathName` , `Server_Address` ,`Server_Port` , `Rra_Resolution` ) REFERENCES `rrdb`.`RRA` (`Rra_CfName` , `Ds_Name` , `Rrd_FilePathName` ,`Server_Address` , `Server_Port` , `Rra_Resolution` ) ON DELETE CASCADE ON UPDATE CASCADE)ENGINE = InnoDB;-- ------------------------------------------------------- Table `rrdb`.`ROWS_COUNTER`-- -----------------------------------------------------CREATE TABLE IF NOT EXISTS `rrdb`.`ROWS_COUNTER` ( `Rra_CfName` VARCHAR(45) NOT NULL , `Rra_Resolution` INT NOT NULL , `Ds_Name` VARCHAR(500) NOT NULL , `Rrd_FilePathName` VARCHAR(500) NOT NULL , `Server_Address` VARCHAR(500) NOT NULL , `Server_Port` INT NOT NULL , `Counter` INT NOT NULL , PRIMARY KEY (`Rra_CfName`, `Ds_Name`, `Rrd_FilePathName`, `Server_Address`,`Server_Port`, `Rra_Resolution`) , INDEX `fk_ROWS_COUNTER_RRA1` (`Rra_CfName` ASC, `Ds_Name` ASC, `Rrd_FilePathName`ASC, `Server_Address` ASC, `Server_Port` ASC, `Rra_Resolution` ASC) , CONSTRAINT `fk_ROWS_COUNTER_RRA1` FOREIGN KEY (`Rra_CfName` , `Ds_Name` , `Rrd_FilePathName` , `Server_Address` ,`Server_Port` , `Rra_Resolution` ) REFERENCES `rrdb`.`RRA` (`Rra_CfName` , `Ds_Name` , `Rrd_FilePathName` ,`Server_Address` , `Server_Port` , `Rra_Resolution` ) ON DELETE CASCADE ON UPDATE CASCADE)ENGINE = InnoDB;-- ------------------------------------------------------- Table `rrdb`.`REPORT`-- -----------------------------------------------------CREATE TABLE IF NOT EXISTS `rrdb`.`REPORT` ( `Report_Id` INT NOT NULL AUTO_INCREMENT , `Rra_CfName` VARCHAR(45) NOT NULL , `Rra_Resolution` INT NOT NULL , `Ds_Name` VARCHAR(500) NOT NULL , `Rrd_FilePathName` VARCHAR(500) NOT NULL , `Server_Address` VARCHAR(500) NOT NULL , `Server_Port` INT NOT NULL , `StatFunction` VARCHAR(45) NOT NULL , `FrequenceUpdate` VARCHAR(45) NOT NULL , `Rows` INT NOT NULL , `Description` VARCHAR(9999) NULL , PRIMARY KEY (`Report_Id`) , INDEX `fk_REPORT_RRA1` (`Rra_CfName` ASC, `Ds_Name` ASC, `Rrd_FilePathName` ASC,`Server_Address` ASC, `Server_Port` ASC, `Rra_Resolution` ASC) , CONSTRAINT `fk_REPORT_RRA1` FOREIGN KEY (`Rra_CfName` , `Ds_Name` , `Rrd_FilePathName` , `Server_Address` ,`Server_Port` , `Rra_Resolution` )Paolo Vanacore 566/1539 Pagina 186 di 279
    • REFERENCES `rrdb`.`RRA` (`Rra_CfName` , `Ds_Name` , `Rrd_FilePathName` ,`Server_Address` , `Server_Port` , `Rra_Resolution` ) ON DELETE CASCADE ON UPDATE CASCADE)ENGINE = InnoDB;-- ------------------------------------------------------- Table `rrdb`.`DATA_REPORT`-- -----------------------------------------------------CREATE TABLE IF NOT EXISTS `rrdb`.`DATA_REPORT` ( `Report_Id` INT NOT NULL , `Data_Time` TIMESTAMP NOT NULL , `Value` DOUBLE NOT NULL , PRIMARY KEY (`Report_Id`, `Data_Time`) , INDEX `fk_DATA_REPORT_REPORT1` (`Report_Id` ASC) , CONSTRAINT `fk_DATA_REPORT_REPORT1` FOREIGN KEY (`Report_Id` ) REFERENCES `rrdb`.`REPORT` (`Report_Id` ) ON DELETE CASCADE ON UPDATE CASCADE)ENGINE = InnoDB;-- ------------------------------------------------------- Table `rrdb`.`REPORT_ROWS_COUNTER`-- -----------------------------------------------------CREATE TABLE IF NOT EXISTS `rrdb`.`REPORT_ROWS_COUNTER` ( `Report_Id` INT NOT NULL , `Counter` INT NOT NULL , PRIMARY KEY (`Report_Id`) , INDEX `fk_REPORT_ROWS_COUNTER_REPORT1` (`Report_Id` ASC) , CONSTRAINT `fk_REPORT_ROWS_COUNTER_REPORT1` FOREIGN KEY (`Report_Id` ) REFERENCES `rrdb`.`REPORT` (`Report_Id` ) ON DELETE CASCADE ON UPDATE CASCADE)ENGINE = InnoDB;DELIMITER //USE rrdb//CREATE PROCEDURE `rrdb`.`insertData` ( IN dataTime TIMESTAMP, IN cfName VARCHAR(45), IN resolution INT, IN dsName VARCHAR(500), IN rrdFilePathName VARCHAR(500), IN serverAddress VARCHAR(500), IN serverPort INT, IN value DOUBLE )BEGIN DECLARE rowsNumber INT; DECLARE maxRows INT; DECLARE dateToDelete TIMESTAMP; SELECT `Counter` INTO rowsNumber FROM `ROWS_COUNTER` WHERE `Rra_CfName` = cfName ANDPaolo Vanacore 566/1539 Pagina 187 di 279
    • `Rra_Resolution` = resolution AND `Ds_Name` = dsName AND `Rrd_FilePathName` = rrdFilePathName AND `Server_Address` = serverAddress AND `Server_Port` = serverPort; SELECT (`Rows`) INTO maxRows FROM `RRA` WHERE `Rra_CfName` = cfName AND `Rra_Resolution` = resolution AND `Ds_Name` = dsName AND `Rrd_FilePathName` = rrdFilePathName AND `Server_Address` = serverAddress AND `Server_Port` = serverPort; IF rowsNumber >= maxRows THEN SELECT MIN(Data_Time) INTO dateToDelete FROM `DATA` WHERE `Rra_CfName` = cfName AND `Rra_Resolution` = resolution AND `Ds_Name` = dsName AND `Rrd_FilePathName` = rrdFilePathName AND `Server_Address` = serverAddress AND `Server_Port` = serverPort; DELETE FROM `DATA` WHERE `Data_Time` = dateToDelete AND `Rra_CfName` = cfName AND `Rra_Resolution` = resolution AND `Ds_Name` = dsName AND `Rrd_FilePathName` = rrdFilePathName AND `Server_Address` = serverAddress AND `Server_Port` = serverPort; END IF; INSERT INTO `DATA` VALUES ( dataTime, cfName, resolution, dsName, rrdFilePathName, serverAddress, serverPort, value );END//CREATE PROCEDURE `rrdb`.`insertDataReport` ( IN reportId INT, IN dataTime TIMESTAMP, IN value DOUBLE )BEGIN DECLARE rowsNumber INT;Paolo Vanacore 566/1539 Pagina 188 di 279
    • DECLARE maxRows INT; DECLARE dateToDelete TIMESTAMP; SELECT `Counter` INTO rowsNumber FROM `REPORT_ROWS_COUNTER` WHERE `Report_Id` = reportId; SELECT (`Rows`) INTO maxRows FROM `REPORT` WHERE `Report_Id` = reportId; IF rowsNumber >= maxRows THEN SELECT MIN(Data_Time) INTO dateToDelete FROM `DATA_REPORT` WHERE `Report_Id` = reportId; DELETE FROM `DATA_REPORT` WHERE `Data_Time` = dateToDelete AND `Report_Id` = reportId; END IF; INSERT INTO `DATA_REPORT` VALUES ( reportId, dataTime, value );END//CREATE TRIGGER `Update_DenyRows` BEFORE UPDATE ON `RRA` FOR EACH ROW BEGIN SET NEW.Rows = OLD.Rows; END;//CREATE TRIGGER `Insert_RowsCounter` AFTER INSERT ON `RRA` FOR EACH ROW BEGIN INSERT INTO `ROWS_COUNTER` VALUES ( NEW.Rra_CfName, NEW.Rra_Resolution, NEW.Ds_Name, NEW.Rrd_FilePathName, NEW.Server_Address, NEW.Server_Port, 0Paolo Vanacore 566/1539 Pagina 189 di 279
    • ); END;//CREATE TRIGGER `AfterInsertUpdateRowsCounter` AFTER INSERT ON `DATA` FOR EACH ROW BEGIN UPDATE `ROWS_COUNTER` SET Counter = Counter + 1 WHERE `Rra_CfName` = NEW.Rra_CfName AND `Rra_Resolution` = NEW.Rra_Resolution AND `Ds_Name` = NEW.Ds_Name AND `Rrd_FilePathName` = NEW.Rrd_FilePathName AND `Server_Address` = NEW.Server_Address AND `Server_Port` = NEW.Server_Port; END;//CREATE TRIGGER `AfterDeleteUpdateRowsCounter` AFTER DELETE ON `DATA` FOR EACH ROW BEGIN UPDATE `ROWS_COUNTER` SET Counter = Counter - 1 WHERE `Rra_CfName` = OLD.Rra_CfName AND `Rra_Resolution` = OLD.Rra_Resolution AND `Ds_Name` = OLD.Ds_Name AND `Rrd_FilePathName` = OLD.Rrd_FilePathName AND `Server_Address` = OLD.Server_Address AND `Server_Port` = OLD.Server_Port; END;//CREATE TRIGGER `BeforeInsertCheckRowsCounter` BEFORE INSERT ON `DATA` FOR EACH ROW BEGIN DECLARE rowsNumber INT; DECLARE maxRows INT; DECLARE dateToDelete TIMESTAMP; SELECT `Counter` INTO rowsNumber FROM `ROWS_COUNTER` WHERE `Rra_CfName` = NEW.Rra_CfName AND `Rra_Resolution` = NEW.Rra_Resolution AND `Ds_Name` = NEW.Ds_Name AND `Rrd_FilePathName` = NEW.Rrd_FilePathName AND `Server_Address` = NEW.Server_Address AND `Server_Port` = NEW.Server_Port; SELECT (`Rows`) INTO maxRowsPaolo Vanacore 566/1539 Pagina 190 di 279
    • FROM `RRA` WHERE `Rra_CfName` = NEW.Rra_CfName AND `Rra_Resolution` = NEW.Rra_Resolution AND `Ds_Name` = NEW.Ds_Name AND `Rrd_FilePathName` = NEW.Rrd_FilePathName AND `Server_Address` = NEW.Server_Address AND `Server_Port` = NEW.Server_Port; IF rowsNumber >= maxRows THEN CALL USE_insertData_PROCEDURE(); END IF; END;//CREATE TRIGGER `Insert_Report_RowsCounter` AFTER INSERT ON `REPORT` FOR EACH ROW BEGIN INSERT INTO `REPORT_ROWS_COUNTER` VALUES ( NEW.Report_Id, 0 ); END;//CREATE TRIGGER `Update_DenyRowsCounter` BEFORE UPDATE ON `REPORT` FOR EACH ROW BEGIN SET NEW.Rows = OLD.Rows; END;//CREATE TRIGGER `BeforeInsertCheckReportRowsCounter` BEFORE INSERT ON `DATA_REPORT` FOR EACH ROW BEGIN DECLARE rowsNumber INT; DECLARE maxRows INT; DECLARE dateToDelete TIMESTAMP; SELECT `Counter` INTO rowsNumber FROM `REPORT_ROWS_COUNTER` WHERE `Report_Id` = NEW.Report_Id; SELECT (`Rows`) INTO maxRows FROM `REPORT` WHERE `Report_Id` = NEW.Report_Id; IF rowsNumber >= maxRows THENPaolo Vanacore 566/1539 Pagina 191 di 279
    • CALL USE_insertDataReport_PROCEDURE(); END IF; END;//CREATE TRIGGER `AfterInsertUpdateReportRowsCounter` AFTER INSERT ON `DATA_REPORT` FOR EACH ROW BEGIN UPDATE `REPORT_ROWS_COUNTER` SET Counter = Counter + 1 WHERE `Report_Id` = NEW.Report_Id; END;//CREATE TRIGGER `AfterDeleteUpdateReportRowsCounter` AFTER DELETE ON `DATA_REPORT` FOR EACH ROW BEGIN UPDATE `REPORT_ROWS_COUNTER` SET Counter = Counter - 1 WHERE `Report_Id` = OLD.Report_Id; END;//DELIMITER ;SET SQL_MODE=@OLD_SQL_MODE;SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS; 7.4.11 WiStat – beanpackage bean;import java.io.Serializable;import java.util.LinkedList;import java.util.StringTokenizer;import java.util.regex.Pattern;import org.jfree.chart.ChartFactory;import org.jfree.chart.JFreeChart;import org.jfree.data.time.FixedMillisecond;import org.jfree.data.time.TimeSeries;import org.jfree.data.time.TimeSeriesCollection;import org.jfree.data.time.TimeSeriesDataItem;public class CompareGraph implements Serializable { private static final long serialVersionUID = -2731274074741937311L; private String name = null; private TimeSeriesCollection dataset = null; private LinkedList<TimeSeries> seriesList = new LinkedList<TimeSeries>(); private String graphResolution = "800x600"; private int width = 800; private int height = 600; private final String[] graphResolutions = {Paolo Vanacore 566/1539 Pagina 192 di 279
    • "320x240", "640x480","800x600", "1024x768", "1280x1024"}; private final String regExRes = "[1-9]+[0-9]*+[xX]+[1-9]+[0-9]*"; public CompareGraph(){} public CompareGraph(String name, String graphResolution){ seriesList = new LinkedList<TimeSeries>(); this.name = name; setGraphResolution(graphResolution); } public void addDataList(LinkedList<Data> dataList, String tag){ seriesList.add(createTimeSeries(dataList, tag)); } public void resetSeriesList(){ seriesList = new LinkedList<TimeSeries>(); } public String getGraphResolution(){ return graphResolution; } public void setGraphResolution(String graphResolution){ if (graphResolution!=null){ if (Pattern.matches(regExRes, graphResolution)){ this.graphResolution = graphResolution; StringTokenizer resolutionToken = new StringTokenizer(graphResolution, "x"); width = Integer.parseInt(resolutionToken.nextToken()); height = Integer.parseInt(resolutionToken.nextToken()); } } } public String[] getGraphResolutions(){ return graphResolutions; } public int getWidth(){ return width; } public int getHeight(){ return height; } public String getName(){ return name; } public void setName(String name){ this.name = name; } private TimeSeries createTimeSeries(LinkedList<Data> dataList, String seriesName) { TimeSeries series = null; if (dataList != null){ series = new TimeSeries(seriesName); if (series != null) for (Data data : dataList){ long time = data.getTimeMilli(); Double value = data.getValue(); try{ series.add(new TimeSeriesDataItem( new FixedMillisecond(time), value)); } catch (Exception ex){ex.printStackTrace(); } } } return series; } private JFreeChart createChart(TimeSeriesCollection dataset) { JFreeChart chart = ChartFactory.createTimeSeriesChart( name, "Time", "Value", dataset, true, // legend true, // tool tips false // URLs ); return chart; } public JFreeChart getChart(){ dataset = new TimeSeriesCollection();Paolo Vanacore 566/1539 Pagina 193 di 279
    • for (TimeSeries series : seriesList) if (series != null) dataset.addSeries(series); JFreeChart chart = createChart(dataset); return chart; }}package bean;import java.io.Serializable;import java.text.DateFormat;import java.text.SimpleDateFormat;public class Data implements Serializable { private static final long serialVersionUID = -8268683346731390423L; private Double value; private long time; public Data(){ value = null; time = 0; } public Data(Double value, long time){ this.value = value; this.time = time; } public Double getValue(){ return value; } public long getTimeMilli(){ return time; } public String getTimeStr(){ DateFormat df = new SimpleDateFormat ("dd/MM/yyyy HH:mm"); return df.format(time); }}package bean;import java.io.Serializable;import java.sql.SQLException;import java.util.Calendar;import java.util.LinkedList;import java.util.StringTokenizer;import java.util.Vector;import database.Rrdb;public class DataBase implements Serializable { private static final long serialVersionUID = 4944714931624825010L; public DataBase(){} public LinkedList<MonitoredData> getMonitoredDataList() throws SQLException, ClassNotFoundException{ Rrdb rrdb = new Rrdb(); try{ rrdb.connect(); Vector<String[]> queryResp = rrdb.queryGetRRAs(); rrdb.disconnect(); LinkedList<MonitoredData> monitoredDataList = new LinkedList<MonitoredData>(); if (queryResp == null || queryResp.size() == 0) return null; for(String[] attrRecord : queryResp){ if (attrRecord != null && attrRecord.length == 8){Paolo Vanacore 566/1539 Pagina 194 di 279
    • monitoredDataList.add( new MonitoredData( attrRecord[0], Integer.parseInt(attrRecord[1]), attrRecord[2], attrRecord[3], attrRecord[4], Integer.parseInt(attrRecord[5]), Integer.parseInt(attrRecord[6]),attrRecord[7] ) ); } } return monitoredDataList; } finally{ rrdb.disconnect(); } } public LinkedList<Data> getDataList(MonitoredData monitoredData) throws ClassNotFoundException, SQLException{ Rrdb rrdb = new Rrdb(); try{ rrdb.connect(); Vector<String[]> queryResp = rrdb.queryGetRRAData( monitoredData.getRra_CfName(), monitoredData.getRra_Resolution(), monitoredData.getDs_Name(), monitoredData.getRrd_FilePathName(), monitoredData.getServer_Address(), monitoredData.getServer_port() ); rrdb.disconnect(); LinkedList<Data> dataList = new LinkedList<Data>(); if (queryResp == null || queryResp.size() == 0) return null; Double value = null; String date = null; for(String[] attrRecord : queryResp){ if (attrRecord != null && attrRecord.length == 2){ date = attrRecord[0]; value = Double.parseDouble(attrRecord[1]); StringTokenizer dateTok = new StringTokenizer(date, "-: ."); int year = Integer.parseInt(dateTok.nextToken()); int month = Integer.parseInt(dateTok.nextToken()) - 1; int day = Integer.parseInt(dateTok.nextToken()); int hour = Integer.parseInt(dateTok.nextToken()); int min = Integer.parseInt(dateTok.nextToken()); int sec = Integer.parseInt(dateTok.nextToken()); Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.YEAR, year); calendar.set(Calendar.MONTH, month); calendar.set(Calendar.DAY_OF_MONTH, day); calendar.set(Calendar.HOUR_OF_DAY, hour); calendar.set(Calendar.MINUTE, min); calendar.set(Calendar.SECOND, sec); dataList.add(new Data( value, calendar.getTimeInMillis())); } } return dataList; } finally{ rrdb.disconnect(); } } public LinkedList<StatisticReport> getReportList()Paolo Vanacore 566/1539 Pagina 195 di 279
    • throws ClassNotFoundException, SQLException{ Rrdb rrdb = new Rrdb(); try{ rrdb.connect(); Vector<String[]> queryResp = rrdb.queryGetReports(); rrdb.disconnect(); LinkedList<StatisticReport> reportList = new LinkedList<StatisticReport>(); if (queryResp == null || queryResp.size() == 0) return null; for(String[] attrRecord : queryResp){ if (attrRecord != null && attrRecord.length == 5){ reportList.add( new StatisticReport( Integer.parseInt(attrRecord[0]), attrRecord[1], attrRecord[2], Integer.parseInt(attrRecord[3]), attrRecord[4], null ) ); } } return reportList; } finally{ rrdb.disconnect(); } } public LinkedList<StatisticReport> getReportList(MonitoredData monitoredData) throws ClassNotFoundException, SQLException{ Rrdb rrdb = new Rrdb(); try{ rrdb.connect(); Vector<String[]> queryResp = rrdb.queryGetReports( monitoredData.getRra_CfName(), monitoredData.getRra_Resolution(), monitoredData.getDs_Name(), monitoredData.getRrd_FilePathName(), monitoredData.getServer_Address(), monitoredData.getServer_port() ); rrdb.disconnect(); LinkedList<StatisticReport> reportList = new LinkedList<StatisticReport>(); if (queryResp == null || queryResp.size() == 0) return null; for(String[] attrRecord : queryResp){ if (attrRecord != null && attrRecord.length == 5){ reportList.add( new StatisticReport( Integer.parseInt(attrRecord[0]), attrRecord[1], attrRecord[2], Integer.parseInt(attrRecord[3]), attrRecord[4], monitoredData ) ); } } return reportList;Paolo Vanacore 566/1539 Pagina 196 di 279
    • } finally{ rrdb.disconnect(); } } public LinkedList<Data> getDataList(StatisticReport statisticReport) throws ClassNotFoundException, SQLException { Rrdb rrdb = new Rrdb(); try{ rrdb.connect(); Vector<String[]> queryResp = rrdb.queryGetReportData(statisticReport.getReportId()); rrdb.disconnect(); LinkedList<Data> dataList = new LinkedList<Data>(); if (queryResp == null || queryResp.size() == 0) return null; Double value = null; String date = null; for(String[] attrRecord : queryResp){ if (attrRecord != null && attrRecord.length == 2){ date = attrRecord[0]; value = Double.parseDouble(attrRecord[1]); StringTokenizer dateTok = new StringTokenizer(date, "-: ."); int year = Integer.parseInt(dateTok.nextToken()); int month = Integer.parseInt(dateTok.nextToken()) - 1; int day = Integer.parseInt(dateTok.nextToken()); int hour = Integer.parseInt(dateTok.nextToken()); int min = Integer.parseInt(dateTok.nextToken()); int sec = Integer.parseInt(dateTok.nextToken()); Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.YEAR, year); calendar.set(Calendar.MONTH, month); calendar.set(Calendar.DAY_OF_MONTH, day); calendar.set(Calendar.HOUR_OF_DAY, hour); calendar.set(Calendar.MINUTE, min); calendar.set(Calendar.SECOND, sec); dataList.add( new Data(value, calendar.getTimeInMillis()) ); } } return dataList; } finally{ rrdb.disconnect(); } }}package bean;import java.io.Serializable;import java.text.NumberFormat;import java.text.SimpleDateFormat;import java.util.LinkedList;import java.util.Locale;import java.util.StringTokenizer;import java.util.regex.Pattern;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.XYAreaRenderer;import org.jfree.chart.renderer.xy.XYBarRenderer;Paolo Vanacore 566/1539 Pagina 197 di 279
    • import org.jfree.chart.renderer.xy.XYErrorRenderer;import org.jfree.chart.renderer.xy.XYItemRenderer;import org.jfree.chart.renderer.xy.XYLine3DRenderer;import org.jfree.chart.renderer.xy.XYSplineRenderer;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.XYSmoothLineAndShapeRenderer;public class Graph implements Serializable { private static final long serialVersionUID = -2465716321614651724L; private String name = null; private DefaultTableXYDataset dataset = null; private LinkedList<XYSeries> seriesList = new LinkedList<XYSeries>(); private String graphType = "Line"; private String graphResolution = "800x600"; private int width = 800; private int height = 600; private final String[] graphTypes = {"Line", "Spline", "Bar", "Area", "Dot", "3DLine"}; private final String[] graphResolutions = { "320x240", "640x480", "800x600", "1024x768", "1280x1024", "1600x1200"}; private final String regExRes = "[1-9]+[0-9]*+[xX]+[1-9]+[0-9]*"; private XYItemRenderer renderer = new XYSmoothLineAndShapeRenderer(); public Graph(){} public Graph(String name, String graphType, String graphResolution){ seriesList = new LinkedList<XYSeries>(); this.name = name; setGraphType(graphType); setGraphResolution(graphResolution); } public void addDataList(LinkedList<Data> dataList, String tag){ seriesList.add(createXYSeries(dataList, tag)); } public String getGraphType(){ return graphType; } public void resetSeriesList(){ seriesList = new LinkedList<XYSeries>(); } public void setGraphType(String graphType){ boolean flag = true; if (graphType.equals("Spline")) renderer = new XYSplineRenderer(); else if (graphType.equals("Line")) renderer = new XYSmoothLineAndShapeRenderer(); else if (graphType.equals("Bar")) renderer = new XYBarRenderer(); else if (graphType.equals("Area")) renderer = new XYAreaRenderer(); else if (graphType.equals("Dot")) renderer = new XYErrorRenderer(); else if (graphType.equals("3DLine")) renderer = new XYLine3DRenderer(); else flag = false; if (flag) this.graphType = graphType; } public String getGraphResolution(){ return graphResolution; }Paolo Vanacore 566/1539 Pagina 198 di 279
    • public void setGraphResolution(String graphResolution){ if (graphResolution!=null){ if (Pattern.matches(regExRes, graphResolution)){ this.graphResolution = graphResolution; StringTokenizer resolutionToken = new StringTokenizer(graphResolution, "x"); width = Integer.parseInt(resolutionToken.nextToken()); height = Integer.parseInt(resolutionToken.nextToken()); } } } public String[] getGraphTypes(){ return graphTypes; } public String[] getGraphResolutions(){ return graphResolutions; } public int getWidth(){ return width; } public int getHeight(){ return height; } public String getName(){ return name; } public void setName(String name){ this.name = name; } private XYSeries createXYSeries(LinkedList<Data> dataList,String seriesName){ XYSeries series = null; if (dataList != null){ series = new XYSeries(seriesName, true, false); if (series != null) for (Data data : dataList){ long time = data.getTimeMilli(); Double value = data.getValue(); try{ series.add(time, value); } catch (Exception ex){ ex.printStackTrace(); } } } return series; } private JFreeChart createChart(TableXYDataset dataset) { StandardXYToolTipGenerator labelGenerator = new StandardXYToolTipGenerator( StandardXYToolTipGenerator.DEFAULT_TOOL_TIP_FORMAT, new SimpleDateFormat("dd/MMM/yyyy hh:mm", Locale.ITALY), NumberFormat.getInstance() ); renderer.setToolTipGenerator(labelGenerator); DateAxis xAxis = new DateAxis("Time"); xAxis.setLowerMargin(0.0); xAxis.setUpperMargin(0.0); NumberAxis yAxis = new NumberAxis("Value"); yAxis.setAutoRangeIncludesZero(true); XYSmoothLineAndShapeRenderer renderer = new XYSmoothLineAndShapeRenderer(); XYPlot plot = new XYPlot(dataset, xAxis, yAxis, renderer);*/ XYPlot plot = new XYPlot(dataset, xAxis, yAxis, renderer); JFreeChart chart=new JFreeChart(name,JfreeChart.DEFAULT_TITLE_FONT,plot,true); return chart; } public JFreeChart getChart(){ dataset = new DefaultTableXYDataset(); for (XYSeries series : seriesList) if (series != null)Paolo Vanacore 566/1539 Pagina 199 di 279
    • dataset.addSeries(series); JFreeChart chart = createChart(dataset); return chart; }}package bean;import java.io.Serializable;import java.util.LinkedList;public class MonitoredData implements Serializable, Comparable<MonitoredData>{ private static final long serialVersionUID = -6905141744835917365L; DataBase db; private String rra_CfName; private int rra_Resolution; private String ds_Name; private String rrd_FilePathName; private String server_Address; private int server_port; private int rows; private String description; public MonitoredData(){ db = new DataBase(); this.rra_CfName = null; this.rra_Resolution = 0; this.ds_Name = null; this.rrd_FilePathName = null; this.server_Address = null; this.server_port = 0; this.rows = 0; this.description = null; } public MonitoredData(String rra_CfName, int rra_Resolution, String ds_Name, String rrd_FilePathName, String server_Address, int server_port, int rows,String description){ db = new DataBase(); this.rra_CfName = rra_CfName; this.rra_Resolution = rra_Resolution; this.ds_Name = ds_Name; this.rrd_FilePathName = rrd_FilePathName; this.server_Address = server_Address; this.server_port = server_port; this.rows = rows; this.description = description; } public LinkedList<Data> getDataList(){ try { return db.getDataList(this); } catch (Exception ex){ ex.printStackTrace(); return null; } } public LinkedList<StatisticReport> getReportList(){ try { return db.getReportList(this); } catch (Exception ex){ ex.printStackTrace();Paolo Vanacore 566/1539 Pagina 200 di 279
    • return null; } } public String getRra_CfName(){ return rra_CfName;} public int getRra_Resolution(){ return rra_Resolution;} public String getDs_Name(){ return ds_Name;} public String getRrd_FilePathName(){ return rrd_FilePathName;} public String getServer_Address(){ return server_Address;} public int getServer_port(){ return server_port;} public int getRows(){ return rows;} public String getDescription(){ return description;} @Override public int compareTo(MonitoredData o) { if (o != null) return description.compareTo(o.getDescription()); else return 0; }}package bean;import java.io.Serializable;import java.sql.SQLException;import java.util.LinkedList;public class MonitoredDataList extends LinkedList<MonitoredData> implements Serializable{ private static final long serialVersionUID = 181750647223998529L; private DataBase database = null; public MonitoredDataList() throws SQLException, ClassNotFoundException{ database = new DataBase(); LinkedList<MonitoredData> monitoredDataList = database.getMonitoredDataList(); if (monitoredDataList != null) for(MonitoredData monitoredData:database.getMonitoredDataList()) this.add(monitoredData); }}package bean;import java.io.Serializable;import java.util.LinkedList; public class StatisticReport implements Serializable { private static final long serialVersionUID = -622769792358938356L; DataBase db; private int reportId; private String statFunction; private String frequenceUpdate; private int rows; private String description; private MonitoredData ofMonitoredData; public StatisticReport(){ db = new DataBase(); reportId = 0; statFunction = null;Paolo Vanacore 566/1539 Pagina 201 di 279
    • frequenceUpdate = null; rows = 0; description = null; ofMonitoredData = null; } public StatisticReport(int reportId, String statFunction, String frequenceUpdate, int rows, String description, MonitoredData ofMonitoredData){ db = new DataBase(); this.reportId = reportId; this.statFunction = statFunction; this.frequenceUpdate = frequenceUpdate; this.rows = rows; this.description = description; this.ofMonitoredData = ofMonitoredData; } public LinkedList<Data> getDataList(){ try { return db.getDataList(this); } catch (Exception ex){ ex.printStackTrace(); return null; } } public int getReportId(){ return reportId; } public String getStatFunction(){ return statFunction; } public String getFrequenceUpdate(){ return frequenceUpdate; } public int getRows(){ return rows; } public String getDescription(){ return description; } public MonitoredData getOfMonitoredData(){ return ofMonitoredData; }} 7.4.12 WiStat – controller (Servlet)package controller;import java.io.IOException;import javax.servlet.RequestDispatcher;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import bean.Graph;public class ChangeSettings extends HttpServlet { private static final long serialVersionUID = 1L; public ChangeSettings() { super(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {Paolo Vanacore 566/1539 Pagina 202 di 279
    • HttpSession session = request.getSession(true); Graph graph = (Graph) session.getAttribute("graph"); String graphType = request.getParameter("graphType"); String graphResolution = request.getParameter("graphResolution"); graph.setGraphType(graphType); graph.setGraphResolution(graphResolution); RequestDispatcher dispatcher; dispatcher = getServletContext().getRequestDispatcher("/index.jsp"); dispatcher.forward(request,response); }}package controller;import java.io.IOException;import java.util.LinkedList;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import org.jfree.chart.ChartUtilities;import org.jfree.chart.JFreeChart;import bean.CompareGraph;import bean.DataBase;import bean.Graph;import bean.MonitoredData;import bean.MonitoredDataList;import bean.StatisticReport;public class Comparator extends HttpServlet { private static final long serialVersionUID = 1L; public Comparator() { super(); } protected void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException { } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getSession(true); MonitoredDataList monitoredDataList = (MonitoredDataList)session.getAttribute("monitoredDataList"); Graph graph = (Graph) session.getAttribute("graph"); String graphResolution = graph.getGraphResolution(); CompareGraph compGraph = new CompareGraph("Comparation", graphResolution); String[] monitorCheckedList = null; String[] reportCheckedList = null; DataBase dataBase = (DataBase) session.getAttribute("dataBase"); LinkedList<StatisticReport> statisticReportList = null; try { //Ciclo sui monitor monitorCheckedList = request.getParameterValues( "monitoredDataCountCheck"); if (monitorCheckedList != null) for (String monitorChecked : monitorCheckedList){ MonitoredData monitoredData = monitoredDataList.get( Integer.parseInt(monitorChecked)); compGraph.addDataList(monitoredData.getDataList(),Paolo Vanacore 566/1539 Pagina 203 di 279
    • monitoredData.getDescription()); } //Ciclo sui report reportCheckedList = request.getParameterValues( "statisticReportCheck"); statisticReportList = dataBase.getReportList(); if (reportCheckedList != null) for (StatisticReport report : statisticReportList){ for(String reportChecked : reportCheckedList) if (report.getReportId() == Integer.parseInt(reportChecked)) compGraph.addDataList(report.getDataList(), report.getDescription()); } } catch(Exception ex){ ex.printStackTrace(); } JFreeChart chart = compGraph.getChart(); response.setContentType( "image/png" ); java.io.OutputStream out = response.getOutputStream(); ChartUtilities.writeChartAsPNG(out, chart, compGraph.getWidth(), compGraph.getHeight()); out.flush(); out.close(); }}package controller;import java.io.IOException;import java.sql.SQLException;import java.util.LinkedList;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import org.jfree.chart.ChartUtilities;import org.jfree.chart.JFreeChart;import bean.Data;import bean.DataBase;import bean.Graph;import bean.MonitoredData;import bean.MonitoredDataList;public class MonitoredDataGraph extends HttpServlet { private static final long serialVersionUID = 1L; public MonitoredDataGraph() { super(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getSession(true); MonitoredDataList monitoredDataList = (MonitoredDataList)session.getAttribute("monitoredDataList"); int selectedMonitor = Integer.parseInt( request.getParameter("monitoredDataCount")); MonitoredData monitoredData = monitoredDataList.get(selectedMonitor); Graph graph = (Graph) session.getAttribute("graph"); String graphType = graph.getGraphType(); String graphResolution = graph.getGraphResolution();Paolo Vanacore 566/1539 Pagina 204 di 279
    • try { LinkedList<Data> dataList = new DataBase().getDataList(monitoredData); if ( dataList != null ){ graph = new Graph(monitoredData.getDescription(), graphType,graphResolution); graph.addDataList(dataList, monitoredData.getDescription()); JFreeChart chart = graph.getChart(); response.setContentType( "image/png" ); java.io.OutputStream out = response.getOutputStream(); ChartUtilities.writeChartAsPNG(out, chart, graph.getWidth(),graph.getHeight()); out.flush(); out.close(); } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}}package controller;import java.io.IOException;import java.util.LinkedList;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import org.jfree.chart.ChartUtilities;import org.jfree.chart.JFreeChart;import bean.Data;import bean.DataBase;import bean.Graph;import bean.MonitoredData;import bean.MonitoredDataList;import bean.StatisticReport;public class StatisticGraph extends HttpServlet { private static final long serialVersionUID = 1L; public StatisticGraph() { super(); } protected void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getSession(true); MonitoredDataList monitoredDataList = (MonitoredDataList)session.getAttribute("monitoredDataList"); int selectedMonitor = Integer.parseInt( request.getParameter("monitoredDataCount")); int selectedReport = Integer.parseInt(request.getParameter("reportId")); Graph graph = (Graph) session.getAttribute("graph"); String graphType = graph.getGraphType();Paolo Vanacore 566/1539 Pagina 205 di 279
    • String graphResolution = graph.getGraphResolution(); MonitoredData monitoredData = monitoredDataList.get(selectedMonitor); java.io.OutputStream out = response.getOutputStream(); LinkedList<StatisticReport> statisticReportList = null; try { statisticReportList = ( new DataBase()).getReportList(monitoredData); if (statisticReportList != null) for (StatisticReport report : statisticReportList){ if (report.getReportId() == selectedReport){ LinkedList<Data> dataList = report.getDataList(); if (dataList != null){ graph = new Graph(monitoredData.getDescription(), graphType, graphResolution); graph.addDataList(dataList, report.getDescription()); JFreeChart chart = graph.getChart(); response.setContentType("image/png"); ChartUtilities.writeChartAsPNG(out, chart, graph.getWidth(),graph.getHeight()); out.flush(); out.close(); } } } } catch (Exception ex) { ex.printStackTrace(); } } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}} 7.4.13 Wistat – databasepackage database;import org.xml.sax.ErrorHandler;import org.xml.sax.SAXException;import org.xml.sax.SAXParseException;public class DatabaseConfiguration implements ErrorHandler{ //Pathname al file xml di configurazione private String configPath = "./workspace/WiStat/WebContent/WEB-INF/config/wistat_config.xml"; private String rrdbName = null; //Nome del database rrdb private String rrdbUserName = null; //Nome utente per il database rrdb private String rrdbUserPwd = null; //Password utente database rrdb //Unica istanza della classe ServerConfiguration private static final DatabaseConfiguration singleton = new DatabaseConfiguration(); private DatabaseConfiguration(){ rrdbName = "rrdb"; rrdbUserName = "root";Paolo Vanacore 566/1539 Pagina 206 di 279
    • rrdbUserPwd = "scope01"; } public static DatabaseConfiguration getInstance(){ return singleton; } public String getConfigPath(){ return configPath; } public String getRrdbName(){ return rrdbName; } public String getRrdbUserName(){ return rrdbUserName; } public String getRrdbUserPwd(){ return rrdbUserPwd; } public void error(SAXParseException ex) throws SAXException {} public void fatalError(SAXParseException ex) throws SAXException {} public void warning(SAXParseException ex) throws SAXException {}}package database;import java.sql.*;import java.util.Vector;public class MysqlDatabase { private String dbName = null; //Nome del Database private String userName = null; //Nome utente per Database private String userPwd = null; //Password utente Database private Connection db = null; //Connessione al Database //Stato della connessione (true: connesso; false: non connesso) private boolean connStatus; public MysqlDatabase (String dbName, String userName, String userPwd){ this.dbName = dbName; this.userName = userName; this.userPwd = userPwd; connStatus = false; } public String getDbName(){ return dbName; } public String getUserName(){ return userName; } public String getUserPwd(){ return userPwd; } public void connect() throws ClassNotFoundException, SQLException{ connStatus = false; //Carica driver JDBC Class.forName("com.mysql.jdbc.Driver"); //Effettua la connessione db = DriverManager.getConnection("jdbc:mysql://localhost/"+dbName + "?user=" + userName+ "&password="+ userPwd); //Connessione effettuata connStatus = true; } public Vector<String[]> query(String query) throws SQLException { Vector<String[]> result = null; String [] record; int colums = 0; //Statement per lesecuzione della query Statement statement = db.createStatement(); //ResultSet dellesecuzione della query ResultSet resultSet = statement.executeQuery(query); //Vettore per i risultati result = new Vector<String[]>(); //ResultSetMetaData del risultato della query ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); //Numero di colonne del risultato della query colums = resultSetMetaData.getColumnCount(); //Scorre il ResultSet e crea il vettore risultato while(resultSet.next()){Paolo Vanacore 566/1539 Pagina 207 di 279
    • record = new String[colums]; for (int i=0; i<colums; i++) record[i] = resultSet.getString(i+1); result.add( (String[])record.clone() ); } resultSet.close(); //Chiusura ResultSet statement.close(); //Chiusura Statement return result; } public void updateQuery(String query) throws SQLException { Statement stmt = db.createStatement(); stmt.executeUpdate(query); stmt.close(); } public void disconnect() { if (db!=null){ try { db.close(); connStatus = false; } catch (Exception e){ e.printStackTrace(); } } } public boolean getConnectionStatus() { return connStatus; }}package database;import java.sql.SQLException;import java.text.DateFormat;import java.text.SimpleDateFormat;import java.util.*;public class Rrdb extends MysqlDatabase{ public Rrdb() { super( DatabaseConfiguration.getInstance().getRrdbName(), DatabaseConfiguration.getInstance().getRrdbUserName(), DatabaseConfiguration.getInstance().getRrdbUserPwd() ); } public Vector<String[]> queryGetRRAs() throws SQLException{ String query = "SELECT " + "Rra_CfName, " + "Rra_Resolution, " + "Ds_Name, " + "Rrd_FilePathName, " + "Server_Address, " + "Server_Port, " + "Rows, " + "Description " + "FROM RRA"; return this.query(query); } public Vector<String[]> queryGetRRAData(String rra_CfName, int rra_Resolution, String ds_Name,Paolo Vanacore 566/1539 Pagina 208 di 279
    • String rrd_FilePathName, String server_Address, int server_Port) throws SQLException{ String query = "SELECT " + "Data_Time, " + "Value " + "FROM DATA " + "WHERE " + "Rra_CfName=" + rra_CfName + " " + "AND " + "Rra_Resolution=" + rra_Resolution + " " + "AND " + "Ds_Name=" + ds_Name + " " + "AND " + "Rrd_FilePathName=" + rrd_FilePathName + " " + "AND " + "Server_Address=" + server_Address + " " + "AND " + "Server_Port=" + server_Port + ";"; return this.query(query); } public Vector<String[]> queryGetRRAtData(String rra_CfName, int rra_Resolution, String ds_Name, String rrd_FilePathName, String server_Address, int server_Port, long fromDate, long toDate) throws SQLException{ DateFormat df = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss"); String fromDateStr = df.format(fromDate); String toDateStr = df.format(toDate); String query = "SELECT " + "Data_Time, " + "Value " + "FROM DATA " + "WHERE " + "Rra_CfName=" + rra_CfName + " " + "AND " + "Rra_Resolution=" + rra_Resolution + " " + "AND " + "Ds_Name=" + ds_Name + " " + "AND " + "Rrd_FilePathName=" + rrd_FilePathName + " " + "AND " + "Server_Address=" + server_Address + " " + "AND " + "Server_Port=" + server_Port + "" + "AND " + "Data_Time>=" + fromDateStr + " " + "AND " + "Data_Time<=" + toDateStr + ";"; return this.query(query); } public Vector<String[]> queryGetReports(String cfName, int resolution, String dsName, String rrd_FilePathName, String serverAddress, int serverPort) throws SQLException{ String query = "SELECT REPORT.Report_Id, REPORT.StatFunction, " + "REPORT.FrequenceUpdate, REPORT.Rows, REPORT.Description " + " FROM REPORT JOIN RRA " +Paolo Vanacore 566/1539 Pagina 209 di 279
    • "USING (Rra_CfName, Rra_Resolution, Ds_Name, " + "Rrd_FilePathName, Server_Address, Server_Port) " + "WHERE " + "Rra_CfName = " + cfName + "" + " AND " + "Rra_Resolution = " + resolution + "" + " AND " + "Ds_Name = " + dsName + "" + " AND " + "Rrd_FilePathName = " + rrd_FilePathName + "" + " AND " + "Server_Address = " + serverAddress + "" + " AND " + "Server_Port = " + serverPort + ";"; return this.query(query); } public Vector<String[]> queryGetReports() throws SQLException{ String query = "SELECT REPORT.Report_Id, REPORT.StatFunction, " + "REPORT.FrequenceUpdate, REPORT.Rows, REPORT.Description " + " FROM REPORT "; return this.query(query); } public Vector<String[]> queryGetReportData(int reportId) throws SQLException{ String query = "SELECT " + "Data_Time, " + "Value " + "FROM DATA_REPORT " + "WHERE " + "Report_Id=" + reportId + ";"; return this.query(query); } public Vector<String[]> queryGetReportData(int reportId, long fromDate, long toDate) throws SQLException{ DateFormat df = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss"); String fromDateStr = df.format(fromDate); String toDateStr = df.format(toDate); String query = "SELECT " + "Data_Time, " + "Value " + "FROM DATA_REPORT " + "WHERE " + "Report_Id=" + reportId + " " + "AND " + "Data_Time>=" + fromDateStr + " " + "AND " + "Data_Time<=" + toDateStr + ";"; return this.query(query); }} 7.4.14 WiStat – JSPCompare.jspPaolo Vanacore 566/1539 Pagina 210 di 279
    • <%@ page import="bean.*" %><%@ page import="java.util.Collections" %><jsp:useBean id="monitoredDataList" scope="session"class="bean.MonitoredDataList"/><jsp:useBean id="dataBase" scope="page" class="bean.DataBase"/><form name="CompareForm" action="Comparator" method="POST"> <% monitoredDataList = new MonitoredDataList(); Collections.sort(monitoredDataList); int count = 0; for (MonitoredData monitoredData : monitoredDataList){ out.println("<fieldset>"); out.println("<center><b><input type="checkbox" " + "name="monitoredDataCountCheck" value="" + count + ""/> " + monitoredData.getDescription() + " </b></center><br><br>"); if (dataBase.getReportList(monitoredData)!=null){ for (StatisticReport report : dataBase.getReportList(monitoredData)) out.println("<input type="checkbox" " + "name="statisticReportCheck" + "" value="" + report.getReportId() + ""/>" + report.getDescription() + "<br>"); out.println("<br><br>"); } out.println("</fieldset><br><br>"); count++; } %> <center> <button type="submit"> <b>Compare</b> </button> </center></form>footer.jsp<html> <body> <hr /> <center> <span style="font-family: Courier New,Courier,monospace"> <sub> WiStat Administrator - Paolo Vanacore 566/001539<br> <% out.println(application.getServerInfo()); %> </sub> </span> </center> </body></html>header.jspPaolo Vanacore 566/1539 Pagina 211 di 279
    • <!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=iso-8859-1"/> <script src="jquery-1.2.1.min.js" type="text/javascript"></script> <script src="menu-collapsed.js" type="text/javascript"></script> <link rel="stylesheet" type="text/css" href="style.css" /> <title>WiStatAdim</title></head><body><table border="0" style="width: 80%"> <col /> <col /> <tbody> <tr> <td><img alt="WiStat logo" src="img/logo.wistat.png" width="207" height="121"/> </td> <td> <h1 style="text-align:left;margin-left:0;margin-right:auto;"> <strong> <span style="font-family: Courier New,Courier,monospace"> WiStat@UNINA </span> </strong> </h1> </td> <td style="text-align:down;"> </td> </tr> </tbody></table><hr />index.jsp<%@ page import="bean.*" %><jsp:include page="header.jsp" flush="true"/><jsp:useBean id="graph" scope="session" class="bean.Graph"/><br><br><% session.setMaxInactiveInterval(86400); %><jsp:useBean id="dataBase" scope="session" class="bean.DataBase"/><table border="0" height="100%"> <tr> <td valign="top"> <jsp:include page="menu.jsp" flush="true"/><br><br> </td> <td align="center" width="<% out.print(graph.getWidth()+50); %>" height="<% out.print(graph.getHeight()+50); %>"> <iframe name="central_frame" scrolling="auto" frameborder="0" width="<% out.print(graph.getWidth()+50); %>" height="<% out.print(graph.getHeight()+50); %>"></iframe> </td> <td valign="top"> <jsp:include page="right.jsp" flush="true"/> </td>Paolo Vanacore 566/1539 Pagina 212 di 279
    • </tr></table><jsp:include page="footer.jsp" flush="true"/>menu.jsp<%@ page import="bean.*" %><%@ page import="java.util.LinkedList" %><%@ page import="java.util.Collections" %><jsp:useBean id="monitoredDataList" scope="session"class="bean.MonitoredDataList"/><jsp:useBean id="dataBase" scope="page" class="bean.DataBase"/><ul id="menu"> <li> <a href="Compare.jsp" target="central_frame"> <center><b>COMPARE</b></center></a> </li> <% int count = 0; if (monitoredDataList != null && monitoredDataList.size() > 0){ Collections.sort(monitoredDataList); for (MonitoredData monitoredData : monitoredDataList){ out.println("<li>"); out.println("<a href="" + "MonitoredDataGraph?monitoredDataCount=" + count + "" target="central_frame">" + monitoredData.getDescription() + "</a>"); out.println("<ul>"); LinkedList<StatisticReport> reportList = dataBase.getReportList(monitoredData); if (reportList != null && reportList.size() > 0) for (StatisticReport report : reportList){ out.print("<li>"); out.print(" <a href="" + "StatisticGraph?monitoredDataCount=" + count + "&" + "reportId=" + report.getReportId() + """ + " target="central_frame">" + report.getDescription()+"</a>"); out.print("</li>"); } out.println("</ul>"); out.println("</li>"); count++; } } %></ul>right.jsp<%@page import="bean.Graph"%><jsp:useBean id="graph" scope="session" class="bean.Graph"/><form name="GraphTypeForm" action="ChangeSettings" method="POST">Paolo Vanacore 566/1539 Pagina 213 di 279
    • <fieldset style="width: 100%"> <center><strong>Graphs Settings</strong></center><br> <hr/> <% String[] graphTypes = graph.getGraphTypes(); for (int x = 0; x < graphTypes.length; ++x){ out.print( "<input type="radio" name="graphType"" + " value="" + graphTypes[x] + "" " ); if ((graph.getGraphType()).equals(graphTypes[x])) out.print("checked"); out.println(">" + graphTypes[x] + "<br>"); } %> <hr/> <% String[] graphResolutions = graph.getGraphResolutions(); for (int x = 0; x < graphResolutions.length; ++x){ out.print( "<input type="radio" name="graphResolution"" + " value="" + graphResolutions[x] + "" " ); if ((graph.getGraphResolution()).equals(graphResolutions[x])) out.print("checked"); out.println(">" + graphResolutions[x] + "<br>"); } %> <hr/> <center> <button type="submit" style="background-color:transparent"> <b>set</b> </button> <br> </center> </fieldset></form> 7.4.15 Files di configurazione dellinterfaccia WiStat wistat_config.xml<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE configuration SYSTEM "wistat_config.dtd"><!-- Configuration file for DumperServer --><configuration> <!-- Parametri per laccesso al db --> <rrdb> <!-- Nome del db rrdb --> <dbName>rrdb</dbName> <!-- Nome utente per laccesso al db --> <userName>RrdbUserName</userName> <!-- Password per laccesso al db --> <userPwd>RrdbUserPassword</userPwd> </rrdb></configuration>Paolo Vanacore 566/1539 Pagina 214 di 279
    • wistat_config.dtd<!ELEMENT configuration (rrdb)><!ELEMENT rrdb (dbName, userName, userPwd)><!ELEMENT dbName (#PCDATA)><!ELEMENT userName (#PCDATA)><!ELEMENT userPwd (#PCDATA)> web.xml<?xml version="1.0" encoding="UTF-8"?><web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/j2eehttp://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <display-name>WiStat</display-name> <servlet> <description> </description> <display-name>StatisticGraph</display-name> <servlet-name>StatisticGraph</servlet-name> <servlet-class> controller.StatisticGraph</servlet-class> </servlet> <servlet> <description> </description> <display-name>MonitoredDataGraph</display-name> <servlet-name>MonitoredDataGraph</servlet-name> <servlet-class> controller.MonitoredDataGraph</servlet-class> </servlet> <servlet> <description> </description> <display-name>ChangeSettings</display-name> <servlet-name>ChangeSettings</servlet-name> <servlet-class> controller.ChangeSettings</servlet-class> </servlet> <servlet> <description> </description> <display-name>Comparator</display-name> <servlet-name>Comparator</servlet-name> <servlet-class> controller.Comparator</servlet-class> </servlet> <servlet> <description> </description> <display-name>index</display-name> <servlet-name>index</servlet-name> <servlet-class>Paolo Vanacore 566/1539 Pagina 215 di 279
    • controller.index</servlet-class> </servlet> <servlet-mapping> <servlet-name>StatisticGraph</servlet-name> <url-pattern>/StatisticGraph</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>MonitoredDataGraph</servlet-name> <url-pattern>/MonitoredDataGraph</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>ChangeSettings</servlet-name> <url-pattern>/ChangeSettings</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>Comparator</servlet-name> <url-pattern>/Comparator</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>index</servlet-name> <url-pattern>/index</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list></web-app> 7.4.16 WiStatAdmin – beanpackage bean;import java.io.Serializable;import java.util.LinkedList;public class AvailableFunctionsList extends LinkedList<String> implements Serializable { public AvailableFunctionsList(){}}package bean;import java.io.IOException;import java.io.Serializable;import java.util.LinkedList;import it.unina.scope.wistat.dataclient.net.*;public class DataClient implements Serializable{ private String address = null; private int port = 0; public DataClient(){} public String getAddress(){ return address; }Paolo Vanacore 566/1539 Pagina 216 di 279
    • public int getPort(){ return port; } public void setAddress(String address){ this.address = address; } public void setPort(int port){ this.port = port; } public DataServerList getServerList() throws IOException, ClassNotFoundException{ DataServerList dataServerList = null; DataServerListReq req = new DataServerListReq(); Response resp = req.sendRequest(address, port); DataServerListResp dataServerResp = (DataServerListResp) resp; LinkedList<Server> serverList = dataServerResp.getDataServerList(); dataServerList = new DataServerList(); for (Server server : serverList) dataServerList.add(new DataServer(server.getServerAddr(), server.getServerPort())); return dataServerList; } public void deleteDataServer(DataServer serverToDelete) throws IOException, ClassNotFoundException{ new DeleteDataServerReq( new Server(serverToDelete.getAddr(), serverToDelete.getPort()) ).sendRequest(address, port); } public void addDataServer(DataServer newServer) throws IOException, ClassNotFoundException{ new AddDataServerReq( new Server(newServer.getAddr(), newServer.getPort()) ).sendRequest(address, port); } public DeviceList getDeviceList(DataServer dataServer) throws IOException, ClassNotFoundException{ DeviceListResp response = (DeviceListResp)( new DeviceListReq( new Server( dataServer.getAddr(), dataServer.getPort()) ) ).sendRequest(address, port); DeviceList deviceList = new DeviceList(); for (MonitoredDevice monitDev : response) deviceList.add(new Device(monitDev.getHostname(), monitDev.getDescription())); return deviceList; } publicLinkedList<String>getRrdDeviceList(DataServer dataServer,Device device) throws IOException, ClassNotFoundException{ RrdDeviceListResp response = (RrdDeviceListResp)( new RrdDeviceListReq( new Server( dataServer.getAddr(), dataServer.getPort() ), new MonitoredDevice( device.getHostname(), device.getDescription() ))).sendRequest(address, port); return response; } public Rrd getRrd(DataServer dataServer, String rrdPathname) throws IOException, ClassNotFoundException{Paolo Vanacore 566/1539 Pagina 217 di 279
    • RrdResp rrdResp = (RrdResp) ( new RrdReq( new Server( dataServer.getAddr(), dataServer.getPort() ), rrdPathname )).sendRequest(address, port); LinkedList<Ds> dsList = new LinkedList<Ds>(); for (DsResp dsResp : rrdResp.getDsList()) dsList.add( new Ds( dsResp.getName(), dsResp.getType(), dsResp.getHeartbeat(), dsResp.getMin(), dsResp.getMax() ) ); LinkedList<Rra> rraList = new LinkedList<Rra>(); for (RraResp rraResp : rrdResp.getRraList()) rraList.add( new Rra( rraResp.getCf(), rraResp.getPdpPerRow(), rraResp.getRows(), rraResp.getXff()) ); return new Rrd(rrdResp.getRrdPathname(), rrdResp.getRrdVersion(), rrdResp.getRrdStep(),rrdResp.getRrdLastupdate(),dsList,rraList); } public void addMonitor(DataServer dataServer, String rrdPathname, int step, int pdpPerRow, String dsName, String cfName, String description) throws IOException, ClassNotFoundException{ new AddMonitorReq( rdPathname, step, pdpPerRow, dsName, cfName, new Server( dataServer.getAddr(), dataServer.getPort() ), description ).sendRequest(address, port); } public MonitorList getMonitorList() throws Exception{ MonitorListResp monitorListResp = (MonitorListResp) (new MonitorListReq()).sendRequest(address, port); MonitorList monitorList = new MonitorList(); for (MonitorResp monitorResp : monitorListResp) monitorList.add(new Monitor( monitorResp.getRrdPathname(), new Server( monitorResp.getDataServer().getServerAddr(), monitorResp.getDataServer().getServerPort() ), monitorResp.getDsName(), monitorResp.getCfType(), monitorResp.getRefresh(), monitorResp.getResolution(), monitorResp.getLastupdate(),Paolo Vanacore 566/1539 Pagina 218 di 279
    • monitorResp.getErrorStatus(), monitorResp.getErrorDetails(), monitorResp.getDescription() ) ); return monitorList; } public void deleteMonitor(Monitor monitorToDelete) throws IOException, ClassNotFoundException{ new DeleteMonitorReq( new MonitorResp( monitorToDelete.getRrdPathname(), monitorToDelete.getDataServer(), monitorToDelete.getDsName(), monitorToDelete.getCfType(), monitorToDelete.getRefresh(), monitorToDelete.getResolution(), monitorToDelete.getLastupdate(), monitorToDelete.getErrorStatus(), monitorToDelete.getErrorDetails(), monitorToDelete.getDescription() ) ).sendRequest(address, port); } public ReportList getReportList(Monitor ofMonitor) throws Exception{ ReportList reportList = new ReportList(); ReportListResp reportListResp = (ReportListResp)( new ReportListReq( new MonitorResp( ofMonitor.getRrdPathname(), ofMonitor.getDataServer(), ofMonitor.getDsName(), ofMonitor.getCfType(), ofMonitor.getRefresh(), ofMonitor.getResolution(), ofMonitor.getLastupdate(), ofMonitor.getErrorStatus(), ofMonitor.getErrorDetails(), ofMonitor.getDescription() ) ).sendRequest(address, port) ); for (ReportResp reportResp : reportListResp) reportList.add( new Report( reportResp.getReportId(), reportResp.getStatFunction(), reportResp.getFrequenceUpdate(), reportResp.getRows(), reportResp.getStartTimeMillis(), reportResp.getDescription() ) ); return reportList; } public void deleteReport(Report reportToDelete, Monitor monitorOfReport) throws Exception{ new DeleteReportReq( new ReportResp(Paolo Vanacore 566/1539 Pagina 219 di 279
    • new MonitorResp( monitorOfReport.getRrdPathname(), new Server( monitorOfReport.getDataServer().getServerAddr(), monitorOfReport.getDataServer().getServerPort() ), monitorOfReport.getDsName(), monitorOfReport.getCfType(), monitorOfReport.getRefresh(), monitorOfReport.getResolution(), monitorOfReport.getLastupdate(), monitorOfReport.getErrorStatus(), monitorOfReport.getErrorDetails(), monitorOfReport.getDescription() ), reportToDelete.getReportId(), reportToDelete.getStatFunction(), reportToDelete.getFrequenceUpdate(), reportToDelete.getRows(), reportToDelete.getStartTimeMillis(), reportToDelete.getDescription() ) ).sendRequest(address, port); } public void addReport(Report reportToAdd, Monitor monitorOfReport) throws Exception{ Server dataServer = monitorOfReport.getDataServer(); MonitorResp monitorResp = new MonitorResp( monitorOfReport.getRrdPathname(), dataServer, monitorOfReport.getDsName(), monitorOfReport.getCfType(), monitorOfReport.getRefresh(), monitorOfReport.getResolution(), monitorOfReport.getLastupdate(), monitorOfReport.getErrorStatus(), monitorOfReport.getErrorDetails(), monitorOfReport.getDescription() ); ReportResp reportResp = new ReportResp( monitorResp, reportToAdd.getReportId(), reportToAdd.getStatFunction(), reportToAdd.getFrequenceUpdate(), reportToAdd.getRows(), reportToAdd.getStartTimeMillis(), reportToAdd.getDescription() ); new AddReportReq(reportResp, monitorResp).sendRequest(address, port); } public AvailableFunctionsList getAvailableFunctionList() throws Exception{ AvailableFunctionsResp functionsResp = (AvailableFunctionsResp) ( new AvailableFunctionsReq() ).sendRequest(address, port); AvailableFunctionsList functionsList = new AvailableFunctionsList(); for (String functionStr : functionsResp) functionsList.add(functionStr); return functionsList;Paolo Vanacore 566/1539 Pagina 220 di 279
    • }}package bean;import java.io.Serializable;public class DataServer implements Serializable{ private String addr; private int port; public DataServer(){ addr = null; port = 0; } public DataServer(String addr, int port){ this.addr = addr; this.port = port; } public String getAddr(){ return addr; } public int getPort(){ return port; } public void setAddr(String addr){ this.addr = addr; } public void setPort(int port){ this.port = port; }}package bean;import java.util.LinkedList;public class DataServerList extends LinkedList<DataServer>{ public DataServerList(){}}package bean;import java.io.Serializable;public class Device implements Serializable { private String hostname; private String description; public Device(){ hostname = null; description = null; } public Device(String hostname, String description){ this.hostname = hostname; this.description = description; } public String getHostname(){ return hostname; } public String getDescription(){ return description; } public void setHostname(String hostname){ this.hostname = hostname; } public void setDescription(String description){ this.description = description; }}package bean;import java.util.LinkedList;public class DeviceList extends LinkedList<Device>{ public DeviceList(){}}Paolo Vanacore 566/1539 Pagina 221 di 279
    • package bean;import java.io.Serializable;public class Ds implements Serializable{ private static final long serialVersionUID = -1902596221474684510L; private String name = null; private String type = null; private int heartbeat = 0; private double min = 0.0; private double max = 0.0; public Ds(){} public Ds(String name, String type, int heartbeat, double min, double max){ this.name = name; this.type = type; this.heartbeat = heartbeat; this.min = min; this.max = max; } public String getName(){ return name; } public String getType(){ return type; } public Integer getHeartbeat(){ return heartbeat; } public Double getMin(){ return min; } public Double getMax(){ return max; }}package bean;import it.unina.scope.wistat.dataclient.net.Server;import java.io.Serializable;public class Monitor implements Serializable { private String rrdPathname; private Server dataServer; private String dsName; private String cfType; private int refresh; private int resolution; private int lastupdate; private boolean errorStatus; private String errorDetails; private String description; public Monitor(){ this.rrdPathname = null; this.dataServer = null; this.dsName = null; this.cfType = null; this.refresh = 0; this.resolution = 0; this.lastupdate = 0; this.errorStatus = false; this.errorDetails = null; this.description = null; } public Monitor(String rrdPathname, Server dataServer, String dsName, String cfType, int refresh, int resolution, int lastupdate, boolean errorStatus, String errorDetails, String description){ this.rrdPathname = rrdPathname;Paolo Vanacore 566/1539 Pagina 222 di 279
    • this.dataServer = dataServer; this.dsName = dsName; this.cfType = cfType; this.refresh = refresh; this.resolution = resolution; this.lastupdate = lastupdate; this.errorStatus = errorStatus; this.errorDetails = errorDetails; this.description = description; } public String getRrdPathname(){ return rrdPathname; } public Server getDataServer(){ return dataServer; } public String getDsName(){ return dsName; } public String getCfType(){ return cfType; } public int getRefresh(){ return refresh; } public int getResolution(){ return resolution; } public int getLastupdate(){ return lastupdate; } public boolean getErrorStatus(){ return errorStatus; } public String getErrorDetails(){ return errorDetails; } public String getDescription(){ return description; } public void setRrdPathname(String rrdPathname){ this.rrdPathname = rrdPathname; } public void setDataServer(Server dataServer){ this.dataServer = dataServer; } public void setDsName(String dsName){ this.dsName = dsName; } public void setCfType(String cfType){ this.cfType = cfType; } public void setRefresh(int refresh){ this.refresh = refresh; } public void setResolution(int resolution){ this.resolution = resolution; } public void setLastupdate(int lastupdate){ this.lastupdate = lastupdate; } public void setErrorStatus(boolean errorStatus){ this.errorStatus = errorStatus; } public void setErrorDetails(String errorDetails){ this.errorDetails = errorDetails; } public void setDescription(String description){ this.description = description; }}package bean;import java.io.Serializable;import java.util.LinkedList;public class MonitorList extends LinkedList<Monitor> implements Serializable { public MonitorList(){}}package bean;import it.unina.scope.wistat.dataclient.net.MonitorResp;import it.unina.scope.wistat.dataclient.net.Server;import java.io.Serializable;public class Report implements Serializable { private int reportId = 0;Paolo Vanacore 566/1539 Pagina 223 di 279
    • private String statFunction = null; private String frequenceUpdate = null; private int rows = 0; private long startTimeMillis = 0; private String description = null; public Report(){ reportId = 0; statFunction = null; frequenceUpdate = null; rows = 0; startTimeMillis = 0; description = null; } public Report(int reportId, String statFunction, String frequenceUpdate, int rows, long startTimeMillis, String description){ this.reportId = reportId; this.statFunction = statFunction; this.frequenceUpdate = frequenceUpdate; this.rows = rows; this.startTimeMillis = startTimeMillis; this.description = description; } public Report(String statFunction, String frequenceUpdate, int rows, long startTimeMillis, String description){ this.statFunction = statFunction; this.frequenceUpdate = frequenceUpdate; this.rows = rows; this.startTimeMillis = startTimeMillis; this.description = description; } public int getReportId(){ return reportId; } public String getStatFunction(){ return statFunction; } public String getFrequenceUpdate(){ return frequenceUpdate; } public int getRows(){ return rows; } public long getStartTimeMillis(){ return startTimeMillis; } public String getDescription(){ return description; }}package bean;import java.io.Serializable;import java.util.LinkedList;public class ReportList extends LinkedList<Report> implements Serializable { public ReportList(){}}package bean;import java.io.Serializable;public class Rra implements Serializable{ private static final long serialVersionUID = 8029397766899303172L; private String cf = null; private int pdpPerRow = 0; private int rows = 0; private double xff = 0.0; public Rra(){} public Rra(String cf, int pdpPerRow, int rows, double xff){Paolo Vanacore 566/1539 Pagina 224 di 279
    • this.cf = cf; this.pdpPerRow = pdpPerRow; this.rows = rows; this.xff = xff; } public String getCf(){ return cf; } public int getPdpPerRow(){ return pdpPerRow; } public int getRows(){ return rows; } public double getXff(){ return xff; }}package bean;import java.io.Serializable;import java.util.*;public class Rrd implements Serializable{ private static final long serialVersionUID = 8415568240333780181L; private String pathname = null; private String version = null; private int step; private int lastupdate; private LinkedList<Ds> dsList = null; private LinkedList<Rra> rraList = null; public Rrd(){} public Rrd(String pathname, String version, int step, int lastupdate, LinkedList<Ds> dsList, LinkedList<Rra> rraList){ this.pathname = pathname; this.version = version; this.step = step; this.lastupdate = lastupdate; this.dsList = dsList; this.rraList = rraList; } public String getPathname(){ return pathname; } public String getVersion(){ return version; } public int getStep(){ return step; } public int getLastupdate(){ return lastupdate; } public LinkedList<Ds> getDsList(){ return dsList; } public LinkedList<Rra> getRraList(){ return rraList; }} 7.4.17 WiStatAdmin – controller (Servlet)package controller;import java.io.IOException;import javax.servlet.RequestDispatcher;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import bean.DataClient;import bean.DataServer;import bean.Ds;Paolo Vanacore 566/1539 Pagina 225 di 279
    • import bean.Rra;import bean.Rrd;public class AddMonitorForm extends HttpServlet { private static final long serialVersionUID = 1L; public AddMonitorForm() { super(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{ } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { HttpSession session = request.getSession(true); DataClient dataClient = (DataClient) session.getAttribute("dataClient"); DataServer dataServer = (DataServer) session.getAttribute("dataServer"); Rrd rrd = (Rrd) session.getAttribute("rrd"); Ds ds = (Ds) session.getAttribute("ds"); Rra rra = (Rra) session.getAttribute("rra"); String description = request.getParameter("monitorDescription"); dataClient.addMonitor(dataServer, rrd.getPathname(), rrd.getStep(), rra.getPdpPerRow(), ds.getName(), rra.getCf(), description); } catch(Exception ex){ throw new IOException( "Errore durante laggiunta del monitor.nnDetails:n" + ex); } RequestDispatcher dispatcher; dispatcher = getServletContext().getRequestDispatcher( "/showRrdDetails.jsp"); dispatcher.forward(request,response); }}package controller;import java.io.IOException;import javax.servlet.RequestDispatcher;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import bean.DataClient;public class DataClientForm extends HttpServlet { private static final long serialVersionUID = 1L; public DataClientForm() { super(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{ } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { String dataClientAddr = request.getParameter("DataClientAddr"); int dataClientPort = Integer.parseInt(request.getParameter( "DataClientPort")); HttpSession session = request.getSession(true); DataClient dataClient = (DataClient)session.getAttribute(Paolo Vanacore 566/1539 Pagina 226 di 279
    • "dataClient"); dataClient.setAddress(dataClientAddr); dataClient.setPort(dataClientPort); int sessionTime = Integer.parseInt(request.getParameter( "SessionTime")); session.setMaxInactiveInterval(sessionTime); } catch(Exception ex){ throw new IOException( "Errore durante limpostazione del Data Client.nnDetails:n" + ex); } RequestDispatcher dispatcher; dispatcher = getServletContext().getRequestDispatcher( "/showMonitorAndDataServerForm.jsp"); dispatcher.forward(request,response); }}package controller;import java.io.IOException;import java.util.StringTokenizer;import javax.servlet.RequestDispatcher;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import bean.DataClient;import bean.DataServer;public class DataServerListForm extends HttpServlet { private static final long serialVersionUID = 1L; public DataServerListForm() { super(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {} protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String reqType = request.getParameter("action"); String dataServerStr = request.getParameter("dataServerSelect"); if (dataServerStr != null){ StringTokenizer dataServerTok = new StringTokenizer( dataServerStr,":"); String serverAddr = dataServerTok.nextToken(); String portStr = dataServerTok.nextToken(); if (serverAddr != null && portStr != null){ int serverPort = Integer.parseInt(portStr); DataServer dataServer=new DataServer( serverAddr, serverPort); HttpSession session = request.getSession(true); DataClient dataClient = (DataClient)session.getAttribute( "dataClient"); if (reqType.equals("delete")){ try { dataClient.deleteDataServer(dataServer); } catch(Exception ex){ throw new IOException( "Errore durante la cancellazione del server.nnDetails:n" + ex); }Paolo Vanacore 566/1539 Pagina 227 di 279
    • RequestDispatcher dispatcher; dispatcher = getServletContext().getRequestDispatcher( "/showMonitorAndDataServerForm.jsp"); dispatcher.forward(request,response); } else if (reqType.equals("details")){ session.setAttribute("dataServer", dataServer); RequestDispatcher dispatcher; dispatcher = getServletContext().getRequestDispatcher( "/showDeviceList.jsp"); dispatcher.forward(request,response); } } else { RequestDispatcher dispatcher; dispatcher = getServletContext().getRequestDispatcher( "/showMonitorAndDataServerForm.jsp"); dispatcher.forward(request,response); } } else { RequestDispatcher dispatcher; dispatcher = getServletContext().getRequestDispatcher( "/showMonitorAndDataServerForm.jsp"); dispatcher.forward(request,response); } }}package controller;import java.io.IOException;import javax.servlet.RequestDispatcher;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import bean.Device;public class DeviceListForm extends HttpServlet { private static final long serialVersionUID = 1L; public DeviceListForm() { super(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { HttpSession session = request.getSession(true); String deviceHostname = (String) request.getParameter( "deviceMonitoredSelect"); session.setAttribute("device", new Device(deviceHostname, "")); RequestDispatcher dispatcher; dispatcher = getServletContext().getRequestDispatcher( "/showRrdDeviceList.jsp"); dispatcher.forward(request,response); } catch(Exception ex){ throw new IOException( "Errore durante limpostazione del Data Client.nnDetails:n" + ex);Paolo Vanacore 566/1539 Pagina 228 di 279
    • } }}package controller;import java.io.IOException;import javax.servlet.RequestDispatcher;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import bean.DataClient;import bean.DataServer;import bean.Rrd;public class GenericRrdFileForm extends HttpServlet { private static final long serialVersionUID = 1L; public GenericRrdFileForm() { super(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{ } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { HttpSession session = request.getSession(true); DataClient dataClient = (DataClient) session.getAttribute( "dataClient"); DataServer dataServer = (DataServer) session.getAttribute( "dataServer"); String genericRrdPathname = request.getParameter( "genericRrdFilePath"); Rrd rrd = dataClient.getRrd(dataServer, genericRrdPathname); session.setAttribute("rrd", rrd); RequestDispatcher dispatcher; dispatcher = getServletContext().getRequestDispatcher( "/showRrdDetails.jsp"); dispatcher.forward(request,response); } catch(Exception ex){ throw new IOException( "Errore durante il recupero dellrrd.nnDetails:n" + ex); } }}package controller;import java.io.IOException;import javax.servlet.RequestDispatcher;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;public class loginResponse extends HttpServlet { private static final long serialVersionUID = 1L; public loginResponse() { super(); } protected void doGet(HttpServletRequest request,Paolo Vanacore 566/1539 Pagina 229 di 279
    • HttpServletResponse response) throws ServletException, IOException{ } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getSession(true); session.setAttribute("loginResponse", new String( "Incorrect username or password.")); RequestDispatcher dispatcher; dispatcher = getServletContext().getRequestDispatcher("/login.jsp"); dispatcher.forward(request,response); }}package controller;import java.io.IOException;import javax.servlet.RequestDispatcher;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;public class LogoutForm extends HttpServlet { private static final long serialVersionUID = 1L; public LogoutForm() { super(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getSession(true); session.invalidate(); RequestDispatcher dispatcher; dispatcher = getServletContext().getRequestDispatcher("/logout.jsp"); dispatcher.forward(request,response); }}package controller;import java.io.IOException;import javax.servlet.RequestDispatcher;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import bean.AvailableFunctionsList;import bean.DataClient;import bean.Monitor;import bean.MonitorList;import bean.ReportList;public class MonitorsForm extends HttpServlet { private static final long serialVersionUID = 1L; public MonitorsForm() { super(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{ } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {Paolo Vanacore 566/1539 Pagina 230 di 279
    • HttpSession session = request.getSession(true); DataClient dataClient = (DataClient) session.getAttribute( "dataClient"); MonitorList monitorList = (MonitorList) session.getAttribute( "monitorList"); String reqType = request.getParameter("action"); String monitorSelectStr = request.getParameter("monitorSelect"); RequestDispatcher dispatcher; if(monitorList!=null && monitorList.size()!=0 && monitorSelectStr!=null){ Integer monitorSelectId = Integer.parseInt(monitorSelectStr); if (reqType.equals("delete")){ try { dataClient.deleteMonitor(monitorList.get(monitorSelectId)); dispatcher = getServletContext().getRequestDispatcher( "/showMonitorAndDataServerForm.jsp"); dispatcher.forward(request,response); } catch (Exception ex) { throw new IOException( "Errore durante la cancellazione del monitor.nnDetails:n" + ex); } } else if (reqType.equals("details")){ Monitor monitor = monitorList.get(monitorSelectId); session.setAttribute("monitor", monitor); try { AvailableFunctionsList functionList = dataClient.getAvailableFunctionList(); session.setAttribute("functionList", functionList); ReportList reportList = dataClient.getReportList(monitor); session.setAttribute("reportList", reportList); dispatcher = getServletContext().getRequestDispatcher( "/showMonitorReports.jsp"); dispatcher.forward(request,response); } catch (Exception ex) { throw new IOException( "Errore durante il recupero della lista dei report.nnDetails:n" + ex); } } } else { dispatcher = getServletContext().getRequestDispatcher( "/showMonitorAndDataServerForm.jsp"); dispatcher.forward(request,response); } }}package controller;import java.io.IOException;import javax.servlet.RequestDispatcher;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;Paolo Vanacore 566/1539 Pagina 231 di 279
    • import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import bean.DataClient;import bean.DataServer;public class NewDataServerForm extends HttpServlet { private static final long serialVersionUID = 1L; public NewDataServerForm() { super(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {} protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { String newServerAddr = request.getParameter("newServerAddress"); int newServerPort = Integer.parseInt(request.getParameter( "newServerPort")); HttpSession session = request.getSession(true); DataClient dataClient = (DataClient) session.getAttribute( "dataClient"); dataClient.addDataServer(new DataServer(newServerAddr, newServerPort)); } catch(Exception ex){ throw new IOException( "Errore durante linserimento del nuovo server.nnDetails:n" + ex); } RequestDispatcher dispatcher; dispatcher = getServletContext().getRequestDispatcher( "/showMonitorAndDataServerForm.jsp"); dispatcher.forward(request,response); }}package controller;import it.unina.scope.wistat.dataclient.net.AddReportReq;import java.io.IOException;import java.util.Calendar;import javax.servlet.RequestDispatcher;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import bean.DataClient;import bean.Monitor;import bean.Report;import bean.ReportList;public class NewReportForm extends HttpServlet { private static final long serialVersionUID = 1L; public NewReportForm() { super(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{ } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getSession(true); String functionSelect = request.getParameter("functionSelect"); Integer frequenceTimeValue = Integer.parseInt(request.getParameter( "frequenceTimeValue")); String frequenceTimeUnit = request.getParameter("frequenceTimeUnit");Paolo Vanacore 566/1539 Pagina 232 di 279
    • Integer rows = Integer.parseInt(request.getParameter("rows")); Integer day = Integer.parseInt(request.getParameter("day")); Integer month = Integer.parseInt(request.getParameter("month")); Integer year = Integer.parseInt(request.getParameter("year")); Integer hour = Integer.parseInt(request.getParameter("hour")); Integer minute = Integer.parseInt(request.getParameter("minute")); String description = request.getParameter("description"); DataClient dataClient = (DataClient) session.getAttribute( "dataClient"); Monitor monitor = (Monitor) session.getAttribute("monitor"); Calendar startTime = Calendar.getInstance(); startTime.set(year, month-1, day, hour, minute); Report report = new Report(functionSelect, frequenceTimeUnit + frequenceTimeValue, rows, startTime.getTimeInMillis(), description ); try{ dataClient.addReport(report, monitor); } catch (Exception ex){ throw new IOException( "Errore durante linserimento del nuovo report.nnDetails:n" + ex); } try{ session.setAttribute("reportList", dataClient.getReportList(monitor)); } catch (Exception ex){ throw new IOException( "Errore durante il recupero della lista dei report.nnDetails:n" + ex); } RequestDispatcher dispatcher; dispatcher = getServletContext().getRequestDispatcher( "/showMonitorReports.jsp"); dispatcher.forward(request,response); }}package controller;import java.io.IOException;import javax.servlet.RequestDispatcher;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import bean.AvailableFunctionsList;import bean.DataClient;import bean.Monitor;import bean.MonitorList;import bean.Report;import bean.ReportList;public class ReportListForm extends HttpServlet { private static final long serialVersionUID = 1L; public ReportListForm() { super();} protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{ } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {Paolo Vanacore 566/1539 Pagina 233 di 279
    • HttpSession session = request.getSession(true); DataClient dataClient = (DataClient) session.getAttribute( "dataClient"); ReportList reportList = (ReportList) session.getAttribute( "reportList"); String reqType = request.getParameter("action"); String reportSelectCountStr = request.getParameter( "reportSelectCount"); Report reportSelect = null; if (reportSelectCountStr != null){ Integer reportSelectCount = Integer.parseInt( reportSelectCountStr); reportSelect = reportList.get(reportSelectCount); } RequestDispatcher dispatcher; if (reportList != null && reportList.size() != 0 && reportSelectCountStr != null && reportSelect != null){ if (reqType.equals("delete")){ try { Monitor monitorOfReport = (Monitor) session.getAttribute("monitor"); dataClient.deleteReport(reportSelect, monitorOfReport); session.setAttribute("reportList", dataClient.getReportList(monitorOfReport)); dispatcher = getServletContext().getRequestDispatcher( "/showMonitorReports.jsp"); dispatcher.forward(request,response); } catch (Exception ex) { throw new IOException( "Errore durante la cancellazione del report.nnDetails:n" + ex); } } else if (reqType.equals("details")){ session.setAttribute("report", reportSelect); dispatcher = getServletContext().getRequestDispatcher( "/showReportDetails.jsp"); dispatcher.forward(request,response); } } else { dispatcher = getServletContext().getRequestDispatcher( "/showMonitorReports.jsp"); dispatcher.forward(request,response); } }}package controller;import java.io.IOException;import javax.servlet.RequestDispatcher;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;Paolo Vanacore 566/1539 Pagina 234 di 279
    • import bean.Rrd;public class RrdDetailsForm extends HttpServlet { private static final long serialVersionUID = 1L; public RrdDetailsForm() { super(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{} protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { HttpSession session = request.getSession(true); Rrd rrd = (Rrd) session.getAttribute("rrd"); Integer dsId = Integer.parseInt((String) request.getParameter( "dsSelect")); Integer rraId = Integer.parseInt((String) request.getParameter( "rraSelect")); session.setAttribute("ds", rrd.getDsList().get(dsId)); session.setAttribute("rra", rrd.getRraList().get(rraId)); RequestDispatcher dispatcher; dispatcher = getServletContext().getRequestDispatcher( "/showNewMonitorPreview.jsp"); dispatcher.forward(request,response); } catch(Exception ex){ throw new IOException( "Errore durante limpostazione del Data Client.nnDetails:n" + ex); } }}package controller;import java.io.IOException;import javax.servlet.RequestDispatcher;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import bean.DataClient;import bean.DataServer;import bean.Rrd;public class RrdListForm extends HttpServlet { private static final long serialVersionUID = 1L; public RrdListForm() { super(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { HttpSession session = request.getSession(true); DataClient dataClient = (DataClient) session.getAttribute( "dataClient"); DataServer dataServer = (DataServer) session.getAttribute( "dataServer"); String rrdPathname = request.getParameter("rrdSelect"); Rrd rrd = dataClient.getRrd(dataServer, rrdPathname); session.setAttribute("rrd", rrd); RequestDispatcher dispatcher; dispatcher = getServletContext().getRequestDispatcher(Paolo Vanacore 566/1539 Pagina 235 di 279
    • "/showRrdDetails.jsp"); dispatcher.forward(request,response); } catch(Exception ex){ throw new IOException( "Errore durante il recupero dellrrd.nnDetails:n" + ex); } }} it.unina.scope.wistat.dataclient.netpackage it.unina.scope.wistat.dataclient.net;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.net.Socket;public class AddDataServerReq implements Request { private static final long serialVersionUID = 1944484435745909620L; private Server newServer = null; public AddDataServerReq(Server newServer){ this.newServer = newServer; } public Server getServer(){ return newServer; } public Response sendRequest(String serverAddr, int serverPort) throws IOException, ClassNotFoundException { Socket socket = new Socket(serverAddr, serverPort); //Stream per linvio di oggetti al server ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream()); //Stream per la ricezione di oggetti dal server ObjectInputStream ois = new ObjectInputStream(socket.getInputStream()); Response response = null; try { oos.writeObject(this); //Invia al server la richiesta response = (Response) ois.readObject(); //Riceve risposta server if ( response instanceof ErrorResponse ) throw new IOException( ((ErrorResponse) response).getErrorDetails()); if ( !(response instanceof SuccessResponse) ) throw new IOException("Server response unexpected"); } finally { oos.close(); //Chiusura stream di output associato alla socket ois.close(); //Chiusura stream di input associato alla socket socket.close(); //Chiude la socket } return response; } public void sendResponse(ObjectOutputStream oos) throws IOException { throw new IOException("sendResponse is unsupported on client"); }}package it.unina.scope.wistat.dataclient.net;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;Paolo Vanacore 566/1539 Pagina 236 di 279
    • import java.net.Socket;public class AddMonitorReq implements Request { private static final long serialVersionUID = 3096142063957086280L; private String rrdPathname; private int step; private int pdpPerRow; private String dsName; private String cfName; private Server dataServer; private String description; public AddMonitorReq(String rrdPathname, int step, int pdpPerRow, String dsName, String cfName, Server dataServer, String description){ this.rrdPathname = rrdPathname; this.step = step; this.pdpPerRow = pdpPerRow; this.dsName = dsName; this.cfName = cfName; this.dataServer = dataServer; this.description = description; } public Response sendRequest(String serverAddr, int serverPort) throws IOException, ClassNotFoundException { //Socket per comunicare con il server Socket socket = new Socket(serverAddr, serverPort); //Stream per linvio di oggetti al server ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream()); //Stream per la ricezione di oggetti dal server ObjectInputStream ois = new ObjectInputStream(socket.getInputStream()); Response response = null; try { oos.writeObject(this); //Invia al server la richiesta response = (Response) ois.readObject(); //Riceve risposta server if ( response instanceof ErrorResponse ) throw new IOException( ((ErrorResponse) response).getErrorDetails()); if ( !(response instanceof SuccessResponse) ) throw new IOException("Server response unexpected"); } finally { oos.close(); //Chiusura stream di output associato alla socket ois.close(); //Chiusura stream di input associato alla socket socket.close(); //Chiude la socket } return response; } public void sendResponse(ObjectOutputStream oos)throws IOException { throw new IOException("sendResponse is unsupported on client"); }}package it.unina.scope.wistat.dataclient.net;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.net.Socket;public class AddReportReq implements Request {Paolo Vanacore 566/1539 Pagina 237 di 279
    • private static final long serialVersionUID = 8900314555054489918L; ReportResp reportToAdd = null; MonitorResp monitorToListen = null; public AddReportReq(ReportResp reportToAdd, MonitorResp monitorToListen){ this.reportToAdd = reportToAdd; this.monitorToListen = monitorToListen; } public Response sendRequest(String serverAddr, int serverPort) throws IOException, ClassNotFoundException { //Socket per comunicare con il server Socket socket = new Socket(serverAddr, serverPort); //Stream per linvio di oggetti al server ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream()); //Stream per la ricezione di oggetti dal server ObjectInputStream ois = new ObjectInputStream(socket.getInputStream()); Response response = null; try { oos.writeObject(this); //Invia al server la richiesta response = (Response) ois.readObject(); //Riceve risposta server if ( response instanceof ErrorResponse ) throw new IOException( ((ErrorResponse) response).getErrorDetails()); if ( !(response instanceof SuccessResponse) ) throw new IOException("Server response unexpected"); } finally { oos.close(); //Chiusura stream di output associato alla socket ois.close(); //Chiusura stream di input associato alla socket socket.close(); //Chiude la socket } return response; } public void sendResponse(ObjectOutputStream oos)throws IOException { throw new IOException("sendResponse is unsupported on client"); } }package it.unina.scope.wistat.dataclient.net;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.net.Socket;public class AvailableFunctionsReq implements Request { private static final long serialVersionUID = 6835732647181001644L; public Response sendRequest(String serverAddr, int serverPort) throws Exception { //Socket per comunicare con il server Socket socket = new Socket(serverAddr, serverPort); //Stream per linvio di oggetti al server ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream()); //Stream per la ricezione di oggetti dal server ObjectInputStream ois = new ObjectInputStream(socket.getInputStream()); Response response = null; try {Paolo Vanacore 566/1539 Pagina 238 di 279
    • oos.writeObject(this); //Invia al server la richiesta response = (Response) ois.readObject(); //Riceve risposta server if ( response instanceof ErrorResponse ) throw new IOException( ((ErrorResponse) response).getErrorDetails()); if ( !(response instanceof AvailableFunctionsResp) ) throw new IOException("Server response unexpected"); } finally { oos.close(); //Chiusura stream di output associato alla socket ois.close(); //Chiusura stream di input associato alla socket socket.close(); //Chiude la socket } return response; } public void sendResponse(ObjectOutputStream oos) throws Exception { throw new IOException("sendResponse is unsupported on client"); }}package it.unina.scope.wistat.dataclient.net;import java.util.LinkedList;public class AvailableFunctionsResp extends LinkedList<String> implements Response{ private static final long serialVersionUID = -3126397999997492404L;}package it.unina.scope.wistat.dataclient.net;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.net.Socket;public class DataServerListReq implements Request { private static final long serialVersionUID = 4417500257400319882L; public Response sendRequest(String serverAddr, int serverPort) throws IOException, ClassNotFoundException { //Socket per comunicare con il server Socket socket = new Socket(serverAddr, serverPort); //Stream per linvio di oggetti al server ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream()); //Stream per la ricezione di oggetti dal server ObjectInputStream ois = new ObjectInputStream(socket.getInputStream()); Response response = null; try { oos.writeObject(this); //Invia al server la richiesta response = (Response) ois.readObject(); //Riceve risposta server if ( response instanceof ErrorResponse ) throw new IOException( ((ErrorResponse) response).getErrorDetails()); if ( !(response instanceof DataServerListResp) ) throw new IOException("Server response unexpected"); } finally { oos.close(); //Chiusura stream di output associato alla socket ois.close(); //Chiusura stream di input associato alla socket socket.close(); //Chiude la socketPaolo Vanacore 566/1539 Pagina 239 di 279
    • } return response; } public void sendResponse(ObjectOutputStream oos) throws IOException { throw new IOException("sendResponse is unsupported on client"); }}package it.unina.scope.wistat.dataclient.net;import java.util.LinkedList;public class DataServerListResp implements Response { private static final long serialVersionUID = 6387195717740393238L; private LinkedList<Server> dataServerList = null; public DataServerListResp(LinkedList<Server> dataServerList){ this.dataServerList = dataServerList; } public LinkedList<Server> getDataServerList(){ return dataServerList; }}package it.unina.scope.wistat.dataclient.net;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.net.Socket;public class DeleteDataServerReq implements Request{ private Server serverToDelete = null; private static final long serialVersionUID = 6726545229344270109L; public DeleteDataServerReq(Server serverToDelete){ this.serverToDelete = serverToDelete; } public Server getServer(){ return serverToDelete; } public Response sendRequest(String serverAddr, int serverPort) throws IOException, ClassNotFoundException{ //Socket per comunicare con il server Socket socket = new Socket(serverAddr, serverPort); //Stream per linvio di oggetti al server ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream()); //Stream per la ricezione di oggetti dal server ObjectInputStream ois = new ObjectInputStream(socket.getInputStream()); Response response = null; try { oos.writeObject(this); //Invia al server la richiesta response = (Response) ois.readObject(); //Riceve risposta server if ( response instanceof ErrorResponse ) throw new IOException( ((ErrorResponse) response).getErrorDetails()); if ( !(response instanceof SuccessResponse) ) throw new IOException("Server response unexpected"); } finally { oos.close(); //Chiusura stream di output associato alla socket ois.close(); //Chiusura stream di input associato alla socket socket.close(); //Chiude la socketPaolo Vanacore 566/1539 Pagina 240 di 279
    • } return response; } public void sendResponse(ObjectOutputStream oos) throws IOException { throw new IOException("sendResponse is unsupported on client"); }}package it.unina.scope.wistat.dataclient.net;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.net.Socket;public class DeleteMonitorReq implements Request { private static final long serialVersionUID = -5580509393480619764L; private MonitorResp monitorToDelete = null; public DeleteMonitorReq(MonitorResp monitorToDelete){ this.monitorToDelete = monitorToDelete; } public Response sendRequest(String serverAddr, int serverPort) throws IOException, ClassNotFoundException{ //Socket per comunicare con il server Socket socket = new Socket(serverAddr, serverPort); //Stream per linvio di oggetti al server ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream()); //Stream per la ricezione di oggetti dal server ObjectInputStream ois = new ObjectInputStream(socket.getInputStream()); Response response = null; try { oos.writeObject(this); //Invia al server la richiesta response = (Response) ois.readObject(); //Riceve risposta server if ( response instanceof ErrorResponse ) throw new IOException( ((ErrorResponse) response).getErrorDetails()); if ( !(response instanceof SuccessResponse) ) throw new IOException("Server response unexpected"); } finally { oos.close(); //Chiusura stream di output associato alla socket ois.close(); //Chiusura stream di input associato alla socket socket.close(); //Chiude la socket } return response; } public void sendResponse(ObjectOutputStream oos)throws IOException { throw new IOException("sendResponse is unsupported on client"); }}package it.unina.scope.wistat.dataclient.net;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.net.Socket;import java.sql.SQLException;Paolo Vanacore 566/1539 Pagina 241 di 279
    • import java.util.List;import javax.xml.parsers.ParserConfigurationException;import org.xml.sax.SAXException;public class DeleteReportReq implements Request { private static final long serialVersionUID = 3096142063957086280L; ReportResp reportToDelete = null; public DeleteReportReq(ReportResp reportToDelete){ this.reportToDelete = reportToDelete; } public Response sendRequest(String serverAddr, int serverPort) throws IOException, ClassNotFoundException { //Socket per comunicare con il server Socket socket = new Socket(serverAddr, serverPort); //Stream per linvio di oggetti al server ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream()); //Stream per la ricezione di oggetti dal server ObjectInputStream ois = new ObjectInputStream(socket.getInputStream()); Response response = null; try { oos.writeObject(this); //Invia al server la richiesta response = (Response) ois.readObject(); //Riceve risposta server if ( response instanceof ErrorResponse ) throw new IOException( ((ErrorResponse) response).getErrorDetails()); if ( !(response instanceof SuccessResponse) ) throw new IOException("Server response unexpected"); } finally { oos.close(); //Chiusura stream di output associato alla socket ois.close(); //Chiusura stream di input associato alla socket socket.close(); //Chiude la socket } return response; } public void sendResponse(ObjectOutputStream oos)throws IOException { throw new IOException("sendResponse is unsupported on client"); }}package it.unina.scope.wistat.dataclient.net;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.net.Socket;public class DeviceListReq implements Request { private static final long serialVersionUID = 2368692290753088537L; private Server dataServerSet = null; public DeviceListReq(Server dataServerSet){ this.dataServerSet = dataServerSet; } public Response sendRequest(String serverAddr, int serverPort) throws IOException, ClassNotFoundException { //Socket per comunicare con il server Socket socket = new Socket(serverAddr, serverPort);Paolo Vanacore 566/1539 Pagina 242 di 279
    • //Stream per linvio di oggetti al server ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream()); //Stream per la ricezione di oggetti dal server ObjectInputStream ois = new ObjectInputStream(socket.getInputStream()); Response response = null; try { oos.writeObject(this); //Invia al server la richiesta response = (Response) ois.readObject(); //Riceve risposta server if ( response instanceof ErrorResponse ) throw new IOException( ((ErrorResponse) response).getErrorDetails()); if ( !(response instanceof DeviceListResp) ) throw new IOException("Server response unexpected"); } finally { oos.close(); //Chiusura stream di output associato alla socket ois.close(); //Chiusura stream di input associato alla socket socket.close(); //Chiude la socket } return response; } public void sendResponse(ObjectOutputStream oos) throws IOException { throw new IOException("sendResponse is unsupported on client"); }}package it.unina.scope.wistat.dataclient.net;import java.util.LinkedList;public class DeviceListResp extends LinkedList<MonitoredDevice> implements Response{ private static final long serialVersionUID = 2300464095062479458L;}package it.unina.scope.wistat.dataclient.net;import java.io.Serializable;public class DsResp implements Serializable{ private static final long serialVersionUID = -1902596221474684510L; private String name = null; private String type = null; private int heartbeat = 0; private double min = 0.0; private double max = 0.0; public DsResp(String name,String type,int heartbeat,double min,double max){ this.name = name; this.type = type; this.heartbeat = heartbeat; this.min = min; this.max = max; } public String getName(){ return name; } public String getType(){ return type; } public Integer getHeartbeat(){ return heartbeat; } public Double getMin(){ return min; } public Double getMax(){ return max; }}Paolo Vanacore 566/1539 Pagina 243 di 279
    • package it.unina.scope.wistat.dataclient.net;public class ErrorResponse implements Response { private static final long serialVersionUID = -6010196409281733551L; private String errorDetails = null; public ErrorResponse(String errorDetails){ this.errorDetails = errorDetails; } public String getErrorDetails(){ return errorDetails; }}package it.unina.scope.wistat.dataclient.net;import java.io.Serializable;public class MonitoredDevice implements Serializable{ private static final long serialVersionUID = 3906797826813056798L; private String hostname = null; private String description = null; public MonitoredDevice(String hostname, String description){ this.hostname = hostname; this.description = description; } public String getHostname(){ return hostname; } public String getDescription(){ return description; }}package it.unina.scope.wistat.dataclient.net;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.net.Socket;public class MonitorListReq implements Request { private static final long serialVersionUID = 8494720599394685464L; public Response sendRequest(String serverAddr, int serverPort) throws Exception { //Socket per comunicare con il server Socket socket = new Socket(serverAddr, serverPort); //Stream per linvio di oggetti al server ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream()); //Stream per la ricezione di oggetti dal server ObjectInputStream ois = new ObjectInputStream(socket.getInputStream()); Response response = null; try { oos.writeObject(this); //Invia al server la richiesta response = (Response) ois.readObject(); //Riceve risposta server if ( response instanceof ErrorResponse ) throw new IOException( ((ErrorResponse) response).getErrorDetails()); if ( !(response instanceof MonitorListResp) ) throw new IOException("Server response unexpected"); } finally { oos.close(); //Chiusura stream di output associato alla socket ois.close(); //Chiusura stream di input associato alla socket socket.close(); //Chiude la socketPaolo Vanacore 566/1539 Pagina 244 di 279
    • } return response; } public void sendResponse(ObjectOutputStream oos) throws Exception { throw new IOException("sendResponse is unsupported on client"); }}package it.unina.scope.wistat.dataclient.net;import java.util.LinkedList;public class MonitorListResp extends LinkedList<MonitorResp> implements Response { private static final long serialVersionUID = 4933978189308201591L;}package it.unina.scope.wistat.dataclient.net;public class MonitorResp implements Response { private static final long serialVersionUID = 6652832901015254490L; private String rrdPathname; private Server dataServer; private String dsName; private String cfType; private int refresh; private int resolution; private int lastupdate; private boolean errorStatus; private String errorDetails; private String description; public MonitorResp(String rrdPathname, Server dataServer, String dsName, String cfType, int refresh, int resolution, int lastupdate, boolean errorStatus, String errorDetails, String description){ this.rrdPathname = rrdPathname; this.dataServer = dataServer; this.dsName = dsName; this.cfType = cfType; this.refresh = refresh; this.resolution = resolution; this.lastupdate = lastupdate; this.errorStatus = errorStatus; this.errorDetails = errorDetails; this.description = description; } public String getRrdPathname(){ return rrdPathname; } public Server getDataServer(){ return dataServer; } public String getDsName(){ return dsName; } public String getCfType(){ return cfType; } public int getRefresh(){ return refresh; } public int getResolution(){ return resolution; } public int getLastupdate(){ return lastupdate; } public boolean getErrorStatus(){ return errorStatus; } public String getErrorDetails(){ return errorDetails; } public String getDescription(){ return description; }}package it.unina.scope.wistat.dataclient.net;import java.io.IOException;Paolo Vanacore 566/1539 Pagina 245 di 279
    • import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.net.Socket;public class ReportListReq implements Request { private static final long serialVersionUID = -2233175135204446307L; private MonitorResp monitor = null; public ReportListReq(MonitorResp monitor){ this.monitor = monitor; } public Response sendRequest(String serverAddr, int serverPort) throws Exception { //Socket per comunicare con il server Socket socket = new Socket(serverAddr, serverPort); //Stream per linvio di oggetti al server ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream()); //Stream per la ricezione di oggetti dal server ObjectInputStream ois = new ObjectInputStream(socket.getInputStream()); Response response = null; try { oos.writeObject(this); //Invia al server la richiesta response = (Response) ois.readObject(); //Riceve risposta server if ( response instanceof ErrorResponse ) throw new IOException( ((ErrorResponse) response).getErrorDetails()); if ( !(response instanceof ReportListResp) ) throw new IOException("Server response unexpected"); } finally { oos.close(); //Chiusura stream di output associato alla socket ois.close(); //Chiusura stream di input associato alla socket socket.close(); //Chiude la socket } return response; } public void sendResponse(ObjectOutputStream oos) throws Exception { throw new IOException("sendResponse is unsupported on client"); }}package it.unina.scope.wistat.dataclient.net;import java.util.LinkedList;public class ReportListResp extends LinkedList<ReportResp> implements Response { private static final long serialVersionUID = 665944430100264043L;}package it.unina.scope.wistat.dataclient.net;public class ReportResp implements Response { private static final long serialVersionUID = 8564783838070322444L; private MonitorResp monitor = null; private int reportId = 0; private String statFunction = null; private String frequenceUpdate = null; private int rows = 0; private long startTimeMillis = 0; private String description = null;Paolo Vanacore 566/1539 Pagina 246 di 279
    • public ReportResp(MonitorResp monitor, int reportId, String statFunction, String frequenceUpdate, int rows, long startTimeMillis, String description){ this.monitor = monitor; this.reportId = reportId; this.statFunction = statFunction; this.frequenceUpdate = frequenceUpdate; this.rows = rows; this.startTimeMillis = startTimeMillis; this.description = description; } public MonitorResp getMonitor(){ return monitor; } public int getReportId(){ return reportId; } public String getStatFunction(){ return statFunction; } public String getFrequenceUpdate(){ return frequenceUpdate; } public int getRows(){ return rows; } public long getStartTimeMillis(){ return startTimeMillis; } public String getDescription(){ return description; }}package it.unina.scope.wistat.dataclient.net;import java.io.ObjectOutputStream;import java.io.Serializable;public interface Request extends Serializable { public Response sendRequest(String serverAddr, int serverPort) throws Exception; public void sendResponse(ObjectOutputStream oos) throws Exception;}package it.unina.scope.wistat.dataclient.net;import java.io.Serializable;public interface Response extends Serializable {}package it.unina.scope.wistat.dataclient.net;import java.io.Serializable;public class RraResp implements Serializable{ private static final long serialVersionUID = 8029397766899303172L; private String cf = null; private int pdpPerRow = 0; private int rows = 0; private double xff = 0.0; public RraResp(String cf, int pdpPerRow, int rows, double xff){ this.cf = cf; this.pdpPerRow = pdpPerRow; this.rows = rows; this.xff = xff; } public String getCf(){ return cf; } public int getPdpPerRow(){ return pdpPerRow; } public int getRows(){ return rows; } public double getXff(){ return xff; }}package it.unina.scope.wistat.dataclient.net;import java.io.IOException;Paolo Vanacore 566/1539 Pagina 247 di 279
    • import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.net.Socket;public class RrdDeviceListReq implements Request { private static final long serialVersionUID = 913262712126181544L; private MonitoredDevice device; private Server dataServerSet; public RrdDeviceListReq(Server dataServerSet, MonitoredDevice device){ this.dataServerSet = dataServerSet; this.device = device; } public Response sendRequest(String serverAddr, int serverPort) throws IOException, ClassNotFoundException { //Socket per comunicare con il server Socket socket = new Socket(serverAddr, serverPort); //Stream per linvio di oggetti al server ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream()); //Stream per la ricezione di oggetti dal server ObjectInputStream ois = new ObjectInputStream(socket.getInputStream()); Response response = null; try { oos.writeObject(this); //Invia al server la richiesta response = (Response) ois.readObject(); //Riceve risposta server if ( response instanceof ErrorResponse ) throw new IOException( ((ErrorResponse) response).getErrorDetails()); if ( !(response instanceof RrdDeviceListResp) ) throw new IOException("Server response unexpected"); } finally { oos.close(); //Chiusura stream di output associato alla socket ois.close(); //Chiusura stream di input associato alla socket socket.close(); //Chiude la socket } return response; } public void sendResponse(ObjectOutputStream oos) throws IOException { throw new IOException("sendResponse is unsupported on client"); }}package it.unina.scope.wistat.dataclient.net;import java.util.LinkedList;public class RrdDeviceListResp extends LinkedList<String> implements Response { private static final long serialVersionUID = 7746097408574462762L;}package it.unina.scope.wistat.dataclient.net;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.net.Socket;public class RrdReq implements Request { private static final long serialVersionUID = -3396668592614646499L; private Server dataServerSet = null;Paolo Vanacore 566/1539 Pagina 248 di 279
    • private String rrdPathname; public RrdReq(Server dataServerSet, String rrdPathname){ this.rrdPathname = rrdPathname; this.dataServerSet = dataServerSet; } public Response sendRequest(String serverAddr, int serverPort) throws IOException, ClassNotFoundException { //Socket per comunicare con il server Socket socket = new Socket(serverAddr, serverPort); //Stream per linvio di oggetti al server ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream()); //Stream per la ricezione di oggetti dal server ObjectInputStream ois = new ObjectInputStream(socket.getInputStream()); Response response = null; try { oos.writeObject(this); //Invia al server la richiesta response = (Response) ois.readObject(); //Riceve risposta server if ( response instanceof ErrorResponse ) throw new IOException( ((ErrorResponse) response).getErrorDetails()); if ( !(response instanceof RrdResp) ) throw new IOException("Server response unexpected"); } finally { oos.close(); //Chiusura stream di output associato alla socket ois.close(); //Chiusura stream di input associato alla socket socket.close(); //Chiude la socket } return response; } public void sendResponse(ObjectOutputStream oos) throws IOException { throw new IOException("sendResponse is unsupported on client"); }}package it.unina.scope.wistat.dataclient.net;import java.util.LinkedList;public class RrdResp implements Response { private static final long serialVersionUID = -2400063055038054156L; private String rrdPathname = null; private String rrdVersion = null; private int rrdStep; private int rrdLastupdate; private LinkedList<DsResp> dsList = null; private LinkedList<RraResp> rraList = null; public RrdResp(String rrdPathname, String rrdVersion, int rrdStep, int rrdLastupdate, LinkedList<DsResp> dsList, LinkedList<RraResp> rraList){ this.rrdPathname = rrdPathname; this.rrdVersion = rrdVersion; this.rrdStep = rrdStep; this.rrdLastupdate = rrdLastupdate; this.dsList = dsList; this.rraList = rraList; }Paolo Vanacore 566/1539 Pagina 249 di 279
    • public String getRrdPathname(){ return rrdPathname; } public String getRrdVersion(){ return rrdVersion; } public int getRrdStep(){ return rrdStep; } public int getRrdLastupdate(){ return rrdLastupdate; } public LinkedList<DsResp> getDsList(){ return dsList; } public LinkedList<RraResp> getRraList(){ return rraList; }}package it.unina.scope.wistat.dataclient.net;import java.io.Serializable;public class Server implements Serializable { private static final long serialVersionUID = 3703853210474285773L; private String serverAddr = null; private int serverPort = 0; public Server(String serverAddr, int serverPort){ this.serverAddr = serverAddr; this.serverPort = serverPort; } public String getServerAddr(){ return serverAddr; } public int getServerPort(){ return serverPort; }}package it.unina.scope.wistat.dataclient.net;public class SuccessResponse implements Response { private static final long serialVersionUID = -8200842990859217626L;} 7.4.18 WiStatAdmin – JSPErrorPage.jsp<jsp:include page="header.jsp" flush="true"/><html> <body> <%@ page isErrorPage = "true" %> <br><br> <center> <fieldset style="width: 500px" style="border-color: #CC0000;"> <p> <img alt="punto esclamativo" src="img/punto_esclamativo.jpg" width="76" height="71" /> </p> Siamo spiacenti, si è verificato un errore durante lesecuzione:<br><br> <span style="font-family: Courier New,Courier,monospace"> <sub> <% String error = exception.getMessage(); out.println(error.replace("n", "<br>")); %> <br><br><br><br>Paolo Vanacore 566/1539 Pagina 250 di 279
    • </sub> </span> <form> <input TYPE="button" VALUE="Back" onClick="history.go(-1);"> </form> </fieldset> </center> <br><br> </body></html><jsp:include page="footer.jsp" flush="true"/>footer.jsp<html> <body> <hr /> <center> <span style="font-family: Courier New,Courier,monospace"> <sub> WiStat Administrator - Paolo Vanacore 566/001539<br> <% out.println(application.getServerInfo()); %> </sub> </span> </center> </body></html>header.jsp<!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=iso-8859-1"/> <title>WiStatAdim</title></head><body><table border="0" style="width: 80%"> <col /> <col /> <tbody> <tr> <td> <img alt="WiStat logo" src="img/logo.wistat.png" width="207" height="121"/> </td> <td> <h1 style="text-align:left;margin-left:0;margin-right:auto;"> <strong> <span style="font-family: Courier New,Courier,monospace"> WiStat ADMIN </span>Paolo Vanacore 566/1539 Pagina 251 di 279
    • </strong> </h1> </td> <td style="text-align:down;"> <form name="LogoutForm" action="LogoutForm" method="POST"> <button type="submit"> Logout </button> </form> </td> </tr> </tbody></table><hr />index.jsp<%@ page errorPage="/ErrorPage.jsp" session="true"%><jsp:include page="header.jsp" flush="true"/><br><br><jsp:include page="setDataClient.jsp" flush="true"/><br><br><jsp:include page="footer.jsp" flush="true"/>login.jsp<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd"><html><jsp:useBean id="loginResponse" scope="session" class="java.lang.String"/> <br><br> <h1 style="text-align:center;margin-left:0;margin-right:auto;"> <strong> <span style="font-family: Courier New,Courier,monospace"> Login </span> </strong> </h1><br> <center> <fieldset style="width: 300px; text-align:center;"><br> <form id="login" method="post" action="j_security_check"> Username: <input type="text" name="j_username"/><br> Password: <input type="password" name="j_password"/><br><br> <% if ( (loginResponse != null) && (!loginResponse.equals("")) ) out.println("<font color="#CD3333">" + loginResponse + "</font><br><br>"); %> <input type="submit" value="Login"/> </form> </fieldset> </center> <br><br> <center> <span style="font-family: Courier New,Courier,monospace"> <sub> WiStat Administrator - Paolo Vanacore 566/001539<br> <% out.println(application.getServerInfo()); %>Paolo Vanacore 566/1539 Pagina 252 di 279
    • </sub> </span> </center></html>logout.jsp<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><!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=UTF-8"><title>Insert title here</title></head><body> <br><br><br><br> <center> <fieldset style="width: 300px; text-align:center;"><br> <strong>Logout</strong> eseguito correttamente.<br><br> </fieldset> </center> <br><br> <center> <span style="font-family: Courier New,Courier,monospace"> <sub> WiStat Administrator - Paolo Vanacore 566/001539<br> <% out.println(application.getServerInfo()); %> </sub> </span> </center></body></html>setDataClient.jsp<script language="Javascript"> /* Verifica la presenza di soli numeri in una text area */ function check_onlyNumbers(champ){ var allowChars = new RegExp("[0-9]"); var verif; var points = 0; for(x = 0; x < champ.value.length; x++){ verif = allowChars.test(champ.value.charAt(x)); if(champ.value.charAt(x) == "."){ points++; } if(points > 1){ verif = false; points = 1; } if(verif == false){ champ.value = champ.value.substr(0,x) + champ.value.substr(x+1,champ.value.length-x+1);Paolo Vanacore 566/1539 Pagina 253 di 279
    • x--; } } } /* Cancella il contenuto di una text box */ function eraseText(element){ element.value = ""; }</script><jsp:useBean id="dataClient" scope="session" class="bean.DataClient"/> <center> <fieldset style="width: 500px; text-align:left;"> <form name="DataClientForm" action="DataClientForm" method="POST"> <center> <label><b>Manage DataClient</b></label><br><br> </center> <% String addrStr = dataClient.getAddress(); if (addrStr == null) addrStr = "ip"; String port = Integer.toString(dataClient.getPort()); if (port.equals("0")) port = "port"; out.print("<br><label>Data Client Address:"+ "</label> "+ "<input name="DataClientAddr" value="" + addrStr + "" type="text" size="20" maxlength="50" onfocus="eraseText(this)"/> " + " <label> : </label> <input name="DataClientPort" value="" + port + "" type="text" size="3" maxlength="10"" + "onkeyup="check_onlyNumbers(this)"" + "onfocus="eraseText(this)"/>" ); out.println("<br><br><label> Session Time " + "(sec.):&nbsp&nbsp</sub>" + "<input name="SessionTime"value="" + Integer.toString(session.getMaxInactiveInterval()) + "" type="text" size="3" maxlength="10"" + " onkeyup="check_onlyNumbers(this)"/>" ); %> <br><br> <button type="submit"> Manage </button><br> </form> </fieldset></center>showDataServer.jsp<script language="Javascript"> /* Verifica la presenza di soli numeri in una text area */ function check_onlyNumbers(element){ var allowChars = new RegExp("[0-9]");Paolo Vanacore 566/1539 Pagina 254 di 279
    • var verif; var points = 0; for(x = 0; x < element.value.length; x++){ verif = allowChars.test(element.value.charAt(x)); if(element.value.charAt(x) == "."){ points++; } if(points > 1){ verif = false; points = 1; } if(verif == false){ element.value = element.value.substr(0,x) + element.value.substr(x+1,element.value.length-x+1); x--; } } } /* Cancella il contenuto di una text box */ function eraseText(element){ element.value = ""; } /* Chiede conferma della cancellazione */ function confirmDataServerDelete(){ var dataServer =document.DataServerListForm.dataServerSelect[document.DataServerListForm.dataServerSelect.selectedIndex].value; if (document.DataServerListForm.action[1].checked) return confirm("ATTENZIONE:n" + "questa azione è irreversibile e causa la perdita di tutti i "+ "dati derivanti dal Data Server:nnttt" + dataServer + "nn" + "Eliminare il Data Server? "); }</script><%@ page import="bean.*" %><jsp:useBean id="dataClient" scope="session" class="bean.DataClient"/><table border="1" cellpadding="10" cellspacing="0" bordercolor="white"> <td bgcolor="#E0FFFF"> <% out.println("<sub><A href="index.jsp"><b>DataClient</b></A>:<br>" + dataClient.getAddress() + ":" + dataClient.getPort() +"</sub>"); %> </td></table><br><br><br><br><center> <fieldset style="width: 500px;"><form name="DataServerListForm" action="DataServerListForm" method="POST"onsubmit="return confirmDataServerDelete()"> <center> <label><b>Data Servers</b></label><br><br><br> </center> <% try { DataServerList dataServerList = dataClient.getServerList(); out.println("<select name="dataServerSelect" style="width: 200px;">"); for (DataServer dataServer : dataServerList) out.println("<option value="" + dataServer.getAddr() + ":" + dataServer.getPort() +Paolo Vanacore 566/1539 Pagina 255 di 279
    • "">" + dataServer.getAddr() + ":" + dataServer.getPort() + "</option>"); out.println("</select>"); } catch (Exception ex){ throw new Exception("Errore durante il recupero" + " della lista dei Data Server.nnDetails:n"+ex); } %> <button type="submit"> submit </button><br> <sub> Show Details <input type="radio" name="action" value="details" checked="checked"/> Delete <input type="radio" name="action" value="delete"/> </sub> <br> </form> <br><br><hr /><br><br> <form name="NewDataServerForm" action="NewDataServerForm" method="POST"> <input name="newServerAddress" value="ip" type="text" size="20" maxlength="50" onfocus="eraseText(this)"> <label> : </label> <input name="newServerPort" value="port" type="text" size="3" maxlength="10" onfocus="eraseText(this)" onkeyup="check_onlyNumbers(this)";> <button type="submit"> Add Server </button><br><br><br> </form> </fieldset></center><br><br><br><br>showDeviceList.jsp<script type="text/javascript">/* Cancella il contenuto di una text box */function eraseText(element){ element.value = "";}</script><jsp:include page="header.jsp" flush="true"/><%@ page import="bean.*" %><jsp:useBean id="dataClient" scope="session" class="bean.DataClient"/><jsp:useBean id="dataServer" scope="session" class="bean.DataServer"/><table border="1" cellpadding="10" cellspacing="0" bordercolor="white"> <td bgcolor="#E0FFFF"> <% out.println("<sub><A href="index.jsp"><b>DataClient</b></A>:<br>" + dataClient.getAddress() + ":" + dataClient.getPort() +"</sub>"); %>Paolo Vanacore 566/1539 Pagina 256 di 279
    • </td> <td bgcolor="#C6E2FF"> <% out.println("<sub><Ahref="showMonitorAndDataServerForm.jsp"><b>Data Server</b></A>:<br>" +dataServer.getAddr() + ":" + dataServer.getPort() + "</sub>"); %> </td></table><br><br><br><br><center> <fieldset style="width: 500px;"> <form name="DeviceListForm" action="DeviceListForm" method="POST"> <center> <label><b>Monitored Devices</b></label><br><br><br> </center> <% try { DeviceList deviceMonitoredList = dataClient.getDeviceList(dataServer);out.println("<select name="deviceMonitoredSelect" style="width: 200px;">"); for (Device deviceMonitored : deviceMonitoredList) out.println("<option value="" + deviceMonitored.getHostname() + "">" + deviceMonitored.getHostname() + " (" + deviceMonitored.getDescription() + ") " + "</option>"); out.println("</select>"); } catch (Exception ex){ throw new Exception("Errore durante il recupero della lista dei"+ " Device.nnDetails:n" + ex); } %> <button type="submit"> submit </button><br> <sub> Show Rrd List <input type="radio" name="action" value="showRrdList" checked="checked"/> </sub> <br> </form> <br><br> </fieldset> <br><br> <fieldset style="width: 500px;"><form name="GenericRrdFileForm" action="GenericRrdFileForm" method="POST"> <center> <label><b>Generic Rrd File</b></label><br><br><br> </center><input name="genericRrdFilePath" value="/pathname/to/generic.rrd" type="text"onfocus="eraseText(this)";> <button type="submit"> submit </button><br> <sub> Show Rrd Details <input type="radio" name="action" value="showRrdList" checked="checked"/> </sub>Paolo Vanacore 566/1539 Pagina 257 di 279
    • <br> </form> <br><br> </fieldset></center><br><br><br><br><jsp:include page="footer.jsp" flush="true"/>showMonitorAndDataServerForm.jsp<jsp:include page="header.jsp" flush="false"/><jsp:include page="showDataServer.jsp" flush="false"/><jsp:include page="showMonitorListForm.jsp" flush="false"/><br><br><br><br><jsp:include page="footer.jsp" flush="false"/>showMonitorListForm.jsp<SCRIPT TYPE="text/javascript">function switchTableVisibility(){ var monitorSelect = document.getElementById("monitorSelect"); var monitorLength = monitorSelect.length; var monitorSelectIndex = monitorSelect.selectedIndex; for (x=0; x < monitorLength; ++x) document.getElementById("tableMonitor" + x).style.display = none; document.getElementById("tableMonitor"+monitorSelectIndex).style.display =block;}/* Chiede conferma della cancellazione */function confirmMonitorDelete(){ var monitor =document.showMonitorListForm.monitorSelect[document.showMonitorListForm.monitorSelect.selectedIndex].value; if (document.showMonitorListForm.action[1].checked) return confirm("ATTENZIONE:n" + "questa azione è irreversibile e causa " + "la perdita di tutti i dati derivanti dal Monitor:nnttt" + "monitor id: " + monitor + "nn" + "Eliminare il monitor? ");}</SCRIPT><%@ page import="bean.*" %><jsp:useBean id="dataClient" scope="session" class="bean.DataClient"/><jsp:useBean id="monitorList" scope="session" class="bean.MonitorList"/><center> <fieldset style="width: 700px;"> <center> <label><b>Active Monitors </b> on Data Client <jsp:getProperty property="address" name="dataClient"/>:<jsp:getPropertyproperty="port" name="dataClient"/> </label><br><br> </center><form name="showMonitorListForm" action="MonitorsForm" method="POST"onsubmit="return confirmMonitorDelete()">Paolo Vanacore 566/1539 Pagina 258 di 279
    • <table border="0" cellpadding="10" cellspacing="0" align="center"> <tr> <td align="center" valign="top"style="background-color:"> <% out.println("<sub># Monitor</sub><br>"); monitorList = dataClient.getMonitorList(); session.setAttribute("monitorList", monitorList); int monitorNumber = monitorList.size();out.println("<select name="monitorSelect" id="monitorSelect" style="width:50px;" onchange="switchTableVisibility()">"); int x = 0; for (Monitor monitor : monitorList){ out.println( "<option value="" + x + "">" + x + "</option>" ); ++x; } out.println("</select>"); %> </td> <td rowspan="1"colspan="1"align="right"valign="top"> <br><button type="submit"> Submit </button><br> <sub> Show Reports<input type="radio" name="action" value="details" checked="checked"/><br> Delete Monitor <input type="radio"name="action"value="delete"/> </sub> <br><br> </td> </tr> </table> <% int count = 0; String displayValue = null; java.text.DateFormat df = new java.text.SimpleDateFormat ("dd/MM/yyyy HH:mm.ss"); String lastupdate = null; for (Monitor monitor : monitorList){ if (count == 0) displayValue = "block"; else displayValue = "none"; lastupdate = df.format(new java.util.Date( new Long(monitor.getLastupdate())*1000)); out.println("<div id="tableMonitor" + count + "" style="display:" + displayValue + ";">" + "<table border=0 bordercolor=white style="font-size:13px">" + "<tr bgcolor="#F5F5F5">" + "<td><strong>Monitor #: </strong></td><td>" + count + "</td>" + "</tr>" + "<tr>" +"<td><strong>Description: </strong></td><td>"+monitor.getDescription()+"</td>" + "</tr>" + "<tr bgcolor="#F5F5F5">" +Paolo Vanacore 566/1539 Pagina 259 di 279
    • "<td><strong>Data Server: </strong></td><td>" + monitor.getDataServer().getServerAddr() + ":" + monitor.getDataServer().getServerPort() + "</td>" + "</tr>" + "<tr>" +"<td><strong>Rrd pathname: </strong></td><td>" + monitor.getRrdPathname()+"</td>" + "</tr>" + "<tr bgcolor="#F5F5F5">" +"<td><strong>Data Source: </strong></td><td>" + monitor.getDsName() + "</td>" + "</tr>" + "<tr>" +"<td><strong>Consolidation Function: </strong></td><td>" + monitor.getCfType() + "</td>" + "</tr>" + "<tr bgcolor="#F5F5F5">" +"<td><strong>Resolution: </strong></td><td>" + monitor.getResolution() + "</td>" + "</tr>" + "<tr>" +"<td><strong>Refresh time (sec.): </strong></td><td>" + monitor.getRefresh() + "</td>" + "</tr>" + "<tr bgcolor="#F5F5F5">"); if (monitor.getLastupdate() != 0) out.println( "<td><strong>Lastupdate: </strong></td><td>" + lastupdate + " ("+ monitor.getLastupdate()+ ")</td>" ); else out.println( "<td><strong>Lastupdate: </strong></td><td> - </td>" ); out.println("</tr>" + "<tr>" + "<td><strong>Status: </strong></td>" ); if (monitor.getErrorStatus() && monitor.getLastupdate() != 0) out.println( "<td><font color="#CD3333"><strong> Error </strong></font></td>" + "</tr>" + "<tr bgcolor="#F5F5F5">" + "<td><strong>Error Details: </strong></td><td>" + monitor.getErrorDetails() + "</td>" + "</tr>" ); else if (monitor.getLastupdate() == 0) out.println("<td><font color="#CD3333"> waiting... </font></td>"); else out.println( "<td><font color="#228B22"> ok </font></td>" + "</tr>" ); out.println("</table></div>"); ++count; } %> </form>Paolo Vanacore 566/1539 Pagina 260 di 279
    • </fieldset></center>showMonitorReports.jsp<script language="Javascript"> /* Verifica la presenza di soli numeri in una text area */ function check_onlyNumbers(champ){ var allowChars = new RegExp("[0-9]"); var verif; var points = 0; for(x = 0; x < champ.value.length; x++){ verif = allowChars.test(champ.value.charAt(x)); if(champ.value.charAt(x) == "."){ points++; } if(points > 1){ verif = false; points = 1; } if(verif == false){ champ.value = champ.value.substr(0,x) + champ.value.substr(x+1,champ.value.length-x+1); x--; } } } /* Cancella il contenuto di una text box */ function eraseText(element){ element.value = ""; } /* Chiede conferma della cancellazione del report */ function confirmReportDelete(){ var report =document.ReportListForm.reportSelectCount[document.ReportListForm.reportSelectCount.selectedIndex].value; if (document.ReportListForm.action[1].checked) return confirm("ATTENZIONE:n" +"questa azione e irreversibile e causa la perdita di tutti i dati derivanti dal "+ "report. Eliminare il report? "); } /* Valida una data */ function isValidDate(year, month, day, hour, minute) { year = parseInt(year, 10); month = parseInt(month, 10); day = parseInt(day,10); var dt = new Date(parseInt(year),parseInt(month), parseInt(day), parseInt(hour), parseInt(minute), 0); return ( year+-+month+-+day==dt.getFullYear()+-+dt.getMonth()+ -+dt.getDate() ); } /* Valida un numero */ function isNumber(x){ return ((parseInt(x) + "") == x);} /* Valida il form NewReport */ function validateNewReport(){ var frequenceTimeValue = document.NewReportForm.frequenceTimeValue.value;Paolo Vanacore 566/1539 Pagina 261 di 279
    • var frequenceTimeUnit = document.NewReportForm.frequenceTimeUnit.value; var rows = document.NewReportForm.rows.value; var day = document.NewReportForm.day.value; var month = document.NewReportForm.month.value; var year = document.NewReportForm.year.value; var hour = document.NewReportForm.hour.value; var minute = document.NewReportForm.minute.value; var description = document.NewReportForm.description.value; if ( (frequenceTimeValue < 1) || !isNumber(frequenceTimeValue) ){ alert("Attenzione: frequenza di aggiornamento inserita: "" + frequenceTimeValue + " " + frequenceTimeUnit + """ + "nLa frequenza di aggiornamento del report devessere >= 1."); return false; } if ((rows < 1) || !isNumber(rows)){ alert("Attenzione: numero di record massimo inserito: "" + rows + """ + "nIl numero di record del report devessere >= 1."); return false; } if ( !isNumber(day) || !isNumber(month) || !isNumber(year) || !isNumber(hour) || !isNumber(minute)){alert("Attenzione: formato data errato. E necessario esprimere la data in formatonumerico.n" + "E stato inserito: " + day + "/" + month + "/" + year + " " + hour+ ":" + minute + "nLa data deve rispettare il formato: dd/mm/yyyy hh:mm.nEs.3/4/2010 23:59"); return false; } if (!isValidDate(year, month, day, hour, minute)){ alert("Attenzione: formato data errato.n" +"E stato inserito: " + day + "/" + month + "/" + year + " " + hour + ":" + minute+"nLa data deve rispettare il formato: dd/mm/yyyy hh:mm.nEs. " + "3/4/201023:59"); return false; } if (description == ""){ alert("Attenzione: e necessario inserire una descrizione per il report."); return false; } return true; }</script><jsp:include page="header.jsp" flush="true"/><%@ page import="bean.*" %><jsp:useBean id="dataClient" scope="session" class="bean.DataClient"/><jsp:useBean id="dataServer" scope="session" class="bean.DataServer"/><jsp:useBean id="monitor" scope="session" class="bean.Monitor"/><jsp:useBean id="reportList" scope="session" class="bean.ReportList"/><jsp:useBean id="functionList" scope="session"class="bean.AvailableFunctionsList"/><table border="1" cellpadding="10" cellspacing="0" bordercolor="white"> <td bgcolor="#E0FFFF"><% out.println("<sub><A href="index.jsp"><b>Data Client</b></A>:<br>" +dataClient.getAddress() + ":" + dataClient.getPort() + "</sub>"); %> </td> <td bgcolor="#C6E2FF"> <% out.println("<sub><Ahref="showMonitorAndDataServerForm.jsp"><b>Monitor</b></A> (Data Server - rrdpathname):<br>" + monitor.getDataServer().getServerAddr() + ":" +Paolo Vanacore 566/1539 Pagina 262 di 279
    • monitor.getDataServer().getServerPort() + " - " + monitor.getRrdPathname() +"</sub>"); %> </td></table><br><br><br><br><center> <fieldset style="width: 700px;"><form name="ReportListForm" action="ReportListForm" method="POST" onsubmit="returnconfirmReportDelete()"> <center> <label><b>Active Reports</b></label><br><br><br> </center> <% int count = 0; out.println("<select name="reportSelectCount" style="width: 200px;">"); for (Report report : reportList){ out.println("<option value="" + count + "">" +report.getStatFunction().replace("Camp", "") + " (id: " + report.getReportId() + "- up: " + report.getFrequenceUpdate() + ")" + "</option>"); ++count; } out.println("</select>"); %> <button type="submit"> submit </button><br> <sub> Show Details <input type="radio" name="action" value="details" checked="checked"/> Delete <input type="radio" name="action" value="delete"/> </sub> </form> <br><br><br><hr /><br><br> <center> <label><b>New Report</b></label><br><br><br> </center><table border="0" cellpadding="10" cellspacing="0" bordercolor="white"><form name="NewReportForm" action="NewReportForm" method="POST" onsubmit="returnvalidateNewReport()";> <tr bgcolor="#F0FFFF"> <td> <label style="font-size: 10pt"> Function: </label> </td> <td> <% out.println("<select name="functionSelect" style="width: 100px;">"); for (String function : functionList){ out.println("<option value="" + function + "">" + function.replaceAll("Camp", "") + "</option>"); } out.println("</select>"); %>Paolo Vanacore 566/1539 Pagina 263 di 279
    • </td> </tr> <tr> <td> <label style="font-size: 10pt"> Update Frequence: </label> </td> <td><input name="frequenceTimeValue" value="00" maxlength="2" style="width: 30px;"onfocus="eraseText(this)" onkeyup="check_onlyNumbers(this)";> <select name="frequenceTimeUnit" style="width: 80px;"> <option value="h">hours</option> <option value="d">days</option> <option value="m">months</option> <option value="y">years</option> </select> </td> </tr> <tr bgcolor="#F0FFFF"> <td> <label style="font-size: 10pt">Maxrecords: </label> </td> <td><input name="rows" value="00000" maxlength="5" style="width: 50px;"onfocus="eraseText(this)" onkeyup="check_onlyNumbers(this)";> </td> </tr> <tr> <td><label style="font-size: 10pt"> Start from <sub>dd/mm/yyyy - hh:mm</sub>: </label> </td> <td><input name="day" value="dd" maxlength="2" style="width: 30px;"onfocus="eraseText(this)" onkeyup="check_onlyNumbers(this)";> <label> / </label><input name="month" value="mm" maxlength="2" style="width: 32px;"onfocus="eraseText(this)" onkeyup="check_onlyNumbers(this)";> <label> / </label><input name="year" value="yyyy" maxlength="4" style="width: 60px;"onfocus="eraseText(this)" onkeyup="check_onlyNumbers(this)";> <label>&nbsp - &nbsp</label><input name="hour" value="hh" maxlength="2" style="width: 30px;"onfocus="eraseText(this)" onkeyup="check_onlyNumbers(this)";> :<input name="minute" value="mm" maxlength="2" style="width: 32px;"onfocus="eraseText(this)" onkeyup="check_onlyNumbers(this)";> </td> </tr> <tr bgcolor="#F0FFFF"> <td> <label style="font-size: 10pt">Description:</label> </td> <td> <textarea name="description" style="height:100% width:100%"></textarea> </td> </tr> <tr> <td colspan="2" align="center"> <br> <button type="submit">Paolo Vanacore 566/1539 Pagina 264 di 279
    • Add Report </button> </td> </tr> </form> </table> </fieldset></center><br><br><br><br><jsp:include page="footer.jsp" flush="true"/>showNewMonitorPreview.jsp<jsp:include page="header.jsp" flush="true"/><%@ page import="bean.*" %><jsp:useBean id="dataClient" scope="session" class="bean.DataClient"/><jsp:useBean id="dataServer" scope="session" class="bean.DataServer"/><jsp:useBean id="device" scope="session" class="bean.Device"/><jsp:useBean id="rrd" scope="session" class="bean.Rrd"/><jsp:useBean id="ds" scope="session" class="bean.Ds"/><jsp:useBean id="rra" scope="session" class="bean.Rra"/><table border="1" cellpadding="10" cellspacing="0" bordercolor="white"> <td bgcolor="#E0FFFF"><% out.println("<sub><A href="index.jsp"><b>Data Client</b></A>:<br>" +dataClient.getAddress() + ":" + dataClient.getPort() + "</sub>"); %> </td> <td bgcolor="#C6E2FF"><% out.println("<sub><A href="showMonitorAndDataServerForm.jsp"><b>DataServer</b></A>:<br>" + dataServer.getAddr() + ":" + dataServer.getPort() +"</sub>"); %> </td> <td bgcolor="#D3D3D3"><% out.println("<sub><A href="showDeviceList.jsp"><b>MonitoredDevice</b></A>:<br>" + device.getHostname() + "</sub>"); %> </td> <td bgcolor="#F5F5F5"><% out.println("<sub><A href="showRrdDeviceList.jsp"><b>Rrd file</b></A>:<br>" +rrd.getPathname().substring(rrd.getPathname().lastIndexOf("/") + 1) + "</sub>"); %> </td> <td bgcolor=""><% out.println("<sub><A href="showRrdDetails.jsp"><b>DataSource /RRArchive</b></A>:<br>" + ds.getName() + " / " + rra.getCf() + " ( res. " +rra.getPdpPerRow()*rrd.getStep() + " sec.)</sub>"); %> </td></table><br><br><br><br><center> <form name="AddMonitorForm" action="AddMonitorForm" method="POST"> <fieldset > <center> <label><b>Monitor Summary</b></label><br><br> </center> <span style="font-family: Courier New,Courier,monospace"> <table border="0" cellpadding="10" cellspacing="0" bordercolor="white"> <tr bgcolor="#F5F5F5"> <td>Paolo Vanacore 566/1539 Pagina 265 di 279
    • <strong>Monitor on Data Client:</strong> </td> <td><jsp:getProperty property="address" name="dataClient"/>:<jsp:getPropertyproperty="port" name="dataClient"/> </td> </tr> <tr> <td> <strong>Rrd Pathname:</strong> </td> <td> <jsp:getProperty property="pathname" name="rrd"/> </td> </tr> <tr bgcolor="#F5F5F5"> <td> <strong>Rrd file from Data Server:</strong> </td> <td><jsp:getProperty property="addr" name="dataServer"/>:<jsp:getPropertyproperty="port" name="dataServer"/> </td> </tr> <tr> <td> Refresh rate/resolution: </td> <td> <% int refresh = rrd.getStep()*rra.getPdpPerRow(); String output = refresh + "sec. "; if (refresh >= 60) output += " ~ " + (((long)refresh)/60) + "min. "; if (refresh >= 3600) output += " ~ " + (((long)refresh)/3600) + "h. "; if (refresh >= 86400) output += " ~ " + (((long)refresh)/86400) + "gg. "; if (refresh >= 604800) output +=" ~ " +(((long)refresh)/604800) + "week "; if (refresh >= 2592000) output+=" ~ "+(((long)refresh)/2592000) + "month "; if (refresh >= 31104000) output+=" ~ "+(((long)refresh)/31104000) + "year "; out.println(output); %> </td> </tr> <tr bgcolor="#F5F5F5"> <td> History size: </td> <td> <% int history = rrd.getStep()*rra.getPdpPerRow()*rra.getRows(); output = history + "sec. ";Paolo Vanacore 566/1539 Pagina 266 di 279
    • if (history >= 60) output += " ~ " + (((long)history)/60) + "min. "; if (history >= 3600) output += " ~ " + (((long)history)/3600) + "h. "; if (history >= 86400) output += " ~ " + (((long)history)/86400) + "gg. "; if (history >= 604800) output+=" ~ " + (((long)history)/604800) + "week "; if (history >= 2592000) output+=" ~ "+(((long)history)/2592000) + "month "; if (history >= 31104000) output+=" ~ "+(((long)history)/31104000) + "year "; out.println(output); %> </td> </tr> <tr> <td> <strong>Data Source name:</strong> </td> <td> <jsp:getProperty property="name" name="ds"/> </td> </tr> <tr bgcolor="#F5F5F5"> <td> Data Source type: </td> <td> <jsp:getProperty property="type" name="ds"/> </td> </tr> <tr> <td> <strong>Consolidation function:</strong> </td> <td> <jsp:getProperty property="cf" name="rra"/> </td> </tr> <tr bgcolor="#F5F5F5"> <td> Data domain: </td> <td>[<jsp:getProperty property="min" name="ds"/>, <jsp:getProperty property="max"name="ds"/>] </td> </tr> <tr> <td> <strong>Description:</strong> </td> <td> <input name="monitorDescription" type="text" onfocus="eraseText(this)";> </td> </tr> </table> </span>Paolo Vanacore 566/1539 Pagina 267 di 279
    • </fieldset> <input TYPE="button" VALUE="Back" onClick="history.go(-1);"> <button type="submit"> Add Monitor </button><br> </form></center><br><br><br><br><jsp:include page="footer.jsp" flush="true"/>showReportDetails.jsp<jsp:include page="header.jsp" flush="true"/><%@ page import="bean.*" %><jsp:useBean id="dataClient" scope="session" class="bean.DataClient"/><jsp:useBean id="dataServer" scope="session" class="bean.DataServer"/><jsp:useBean id="monitor" scope="session" class="bean.Monitor"/><jsp:useBean id="report" scope="session" class="bean.Report"/><table border="1" cellpadding="10" cellspacing="0" bordercolor="white"> <td bgcolor="#E0FFFF"><% out.println("<sub><A href="index.jsp"><b>Data Client</b></A>:<br>" +dataClient.getAddress() + ":" + dataClient.getPort() + "</sub>"); %> </td> <td bgcolor="#C6E2FF"><% out.println("<sub><Ahref="showMonitorAndDataServerForm.jsp"><b>Monitor</b></A> (Data Server - rrdpathname):<br>" + monitor.getDataServer().getServerAddr() + ":" +monitor.getDataServer().getServerPort() + " - " + monitor.getRrdPathname() +"</sub>"); %> </td> <td bgcolor="#D3D3D3"> <% out.println("<sub><A href="showMonitorReports.jsp"><b>Report:</b></A>:<br>" + report.getStatFunction().replace("Camp", "") + " (id: " +report.getReportId() + ")" + "</sub>"); %> </td></table><br><br><br><br><center> <fieldset style="width: 500px;"> <center> <label><b>Rrd details</b></label><br><br> </center> <span style="font-family: Courier New,Courier,monospace"> <form name="showDsRraDetailsForm" action="RrdDetailsForm" method="POST"> <table border="0" cellpadding="10" cellspacing="0" align="center"> <tr bgcolor="#F5F5F5"> <td colspan="2" valign="top"> <strong>Report Id:</strong> </td> <td colspan="2" valign="top"> <%out.println(report.getReportId());%> </td> </tr> <tr> <td colspan="2" valign="top"> <strong>Update Time:</strong> </td>Paolo Vanacore 566/1539 Pagina 268 di 279
    • <td colspan="2" valign="top"> <%out.println(report.getFrequenceUpdate());%> </td> </tr> <tr bgcolor="#F5F5F5"> <td colspan="2" valign="top"> <strong>Function:</strong> </td> <td colspan="2" valign="top"> <%out.println(report.getStatFunction().replaceAll("Camp",""));%> </td> </tr> <tr> <td colspan="2" valign="top"> <strong>Max Records:</strong> </td> <td colspan="2" valign="top"> <% out.println(report.getRows()); %> </td> </tr> <tr bgcolor="#F5F5F5"> <td colspan="2" valign="top"> <strong>Description:</strong> </td> <td colspan="2" valign="top"> <% out.println(report.getDescription()); %> </td> </tr> </table> </form> </span> </fieldset> <form><input TYPE="button" VALUE="Back" onClick="history.go(-1);"> </form></center><br><br><br><br><jsp:include page="footer.jsp" flush="true"/>showRrdDetails.jsp<SCRIPT TYPE="text/javascript">function switchTableVisibility(){ var dsSelect = document.getElementById("dsSelect"); var dsLength = dsSelect.length; var dsSelectIndex = dsSelect.selectedIndex; for (x=0; x < dsLength; ++x) document.getElementById("tableDs" + x).style.display = none; document.getElementById("tableDs"+dsSelectIndex).style.display = block; var rraSelect = document.getElementById("rraSelect"); var rraLength = rraSelect.length; var rraSelectIndex = rraSelect.selectedIndex; for (x=0; x < rraLength; ++x) document.getElementById("tableRra" + x).style.display = none;document.getElementById("tableRra"+rraSelectIndex).style.display = block;}</SCRIPT><jsp:include page="header.jsp" flush="true"/><%@ page import="bean.*" %>Paolo Vanacore 566/1539 Pagina 269 di 279
    • <jsp:useBean id="dataClient" scope="session" class="bean.DataClient"/><jsp:useBean id="dataServer" scope="session" class="bean.DataServer"/><jsp:useBean id="device" scope="session" class="bean.Device"/><jsp:useBean id="rrd" scope="session" class="bean.Rrd"/><table border="1" cellpadding="10" cellspacing="0" bordercolor="white"> <td bgcolor="#E0FFFF"><% out.println("<sub><A href="index.jsp"><b>Data Client</b></A>:<br>" +dataClient.getAddress() + ":" + dataClient.getPort() + "</sub>"); %> </td> <td bgcolor="#C6E2FF"><% out.println("<sub><A href="showMonitorAndDataServerForm.jsp"><b>DataServer</b></A>:<br>" + dataServer.getAddr() + ":" + dataServer.getPort() +"</sub>"); %> </td> <td bgcolor="#D3D3D3"><% out.println("<sub><A href="showDeviceList.jsp"><b>MonitoredDevice</b></A>:<br>" + device.getHostname() + "</sub>"); %> </td> <td bgcolor="#F5F5F5"><% out.println("<sub><A href="showRrdDeviceList.jsp"><b>Rrd file</b></A>:<br>" +rrd.getPathname().substring(rrd.getPathname().lastIndexOf("/") + 1) + "</sub>"); %> </td></table><br><br><br><br><center> <fieldset style="width: 1000px;"> <center> <label><b>Rrd details</b></label><br><br> </center> <form name="showDsRraDetailsForm" action="RrdDetailsForm" method="POST"> <table border="0" cellpadding="10" cellspacing="0" align="center"> <tr> <td></td> <td colspan="2" valign="top"> <table border="0" cellpadding="1" cellspacing="10" align="left"> <%java.text.DateFormat df = new java.text.SimpleDateFormat ("dd/MM/yyyy HH:mm.ss");String lastupdate = df.format(new java.util.Date(newLong(rrd.getLastupdate())*1000));out.println("<tr><td>Pathname:</td><td><sub>" + rrd.getPathname() +"</sub></td></tr>");out.println("<tr><td>Last update:</td><td><sub>" + lastupdate +"</sub></td></tr>"); Double step = new Double(rrd.getStep()); String output = step + "sec. "; if (step >= 60) output += " ~ " + (step/60) + "min. "; if (step >= 3600) output += " ~ " + ((step)/3600) + "h. "; if (step >= 86400) output += " ~ " + ((step)/86400) + "gg. "; if (step >= 604800) output += " ~ " + ((step)/604800) + "week "; if (step >= 2592000) output+=" ~ " + ((step)/2592000) + "month "; if (step >= 31104000) output+=" ~ " + ((step)/31104000) + "year "; out.println("<tr><td>Step:</td><td><sub>" + output + "</sub></td></tr>"); out.println("<tr><td>Version:</td><td><sub>" + rrd.getVersion() +Paolo Vanacore 566/1539 Pagina 270 di 279
    • "</sub></td></tr>"); %> </table> </td> <td></td> </tr> <td colspan="4" align="center" valign="top"> <hr /><br> </td> <tr><td rowspan="3" valign="down" style="text-align: left; background-color: #F0FFFF"> <% int count = 0; String displayValue = null; for (Ds ds : rrd.getDsList()){ if (count == 0) displayValue = "block"; else displayValue = "none"; out.println("<div id="tableDs" + count + "" style="display:" + displayValue + ";">" + "<table border=0 bordercolor=white style="font-size:13px">" + "<tr bgcolor="#EEEEE0">" + "<td><strong>Name: </strong></td><td>" + ds.getName() + "</td>" + "</tr>" + "<tr>" + "<td><strong>Type: </strong></td><td>" + ds.getType() + "</td>" + "</tr>" + "<tr bgcolor="#EEEEE0">" +"<td><strong>Heartbeat: </strong></td><td>" + ds.getHeartbeat() + "</td>" + "</tr>" + "<tr>" + "<td><strong>Validity range: </strong></td><td>[" + ds.getMin() + ", " + ds.getMax() + "]</td>" + "</tr>" + "</table></div>" ); ++count; } %> </td> <td align="center" valign="top" style="background-color: #F0FFFF"> <% out.println("<sub><strong>Data Sources</strong></sub><br>");out.println("<select name="dsSelect" id="dsSelect" style="width: 200px;"onchange="switchTableVisibility()">"); int x = 0; for (Ds ds : rrd.getDsList()){ out.println( "<option value="" + x + "">" + ds.getName() + "</option>" ); ++x; } out.println("</select>");Paolo Vanacore 566/1539 Pagina 271 di 279
    • out.println("</td>");out.println("<td align="center" valign="top" style="background-color:#EEEEE0;">");out.println("<sub><strong>Round Robin Archives</strong></sub><br>");out.println("<select name="rraSelect" id="rraSelect" style="width: 200px;"onchange="switchTableVisibility()">"); x = 0; for (Rra rra : rrd.getRraList()){ out.println( "<option value="" + x + "">" + rra.getCf() + " (res. " + rra.getPdpPerRow()*rrd.getStep() + " sec.)" + "</option>" ); ++x; } out.println("</select>"); %> </td><td rowspan="3" valign="down" style="text-align: right; background-color:#EEEEE0;"> <% count = 0; for (Rra rra : rrd.getRraList()){ if (count == 0) displayValue = "block"; else displayValue = "none"; out.println("<div id="tableRra" + count + "" style="display:" + displayValue + ";">" + "<table border=0 bordercolor=white style="font-size:13px">" +"<tr bgcolor="#F0FFFF">" + "<td><strong>Consolidation Function:</strong></td><td>" + rra.getCf() + "</td>" + "</tr>" + "<tr>" +"<td><strong>Pdp per row: </strong></td><td>" + rra.getPdpPerRow() + "</td>" + "</tr>" + "<tr bgcolor="#F0FFFF">" + "<td><strong>Rows: </strong></td><td>" + rra.getRows() + "</td>" + "</tr>" + "<tr>" + "<td><strong>XFileFactor: </strong></td><td>" + rra.getXff() + "</td>" + "</tr> </table></div>" ); ++count; } %> </td> </tr> <tr valign="bottom"> <td rowspan="1" colspan="2" align="center" valign="bottom"> <br><button type="submit"> Set Monitor </button><br> <br> </td>Paolo Vanacore 566/1539 Pagina 272 di 279
    • </tr> <tr colspan="3"> <td rowspan="3" colspan="2" align="center" valign="top"> </td> </tr> </table> </form> </fieldset></center><br><br><br><br><jsp:include page="footer.jsp" flush="true"/>showRrdDeviceList.jsp<jsp:include page="header.jsp" flush="true"/><%@ page import="bean.*" %><jsp:useBean id="dataClient" scope="session" class="bean.DataClient"/><jsp:useBean id="dataServer" scope="session" class="bean.DataServer"/><jsp:useBean id="device" scope="session" class="bean.Device"/><table border="1" cellpadding="10" cellspacing="0" bordercolor="white"> <td bgcolor="#E0FFFF"><% out.println("<sub><A href="index.jsp"><b>Data Client</b></A>:<br>" +dataClient.getAddress() + ":" + dataClient.getPort() + "</sub>"); %> </td> <td bgcolor="#C6E2FF"><% out.println("<sub><A href="showMonitorAndDataServerForm.jsp"><b>DataServer</b></A>:<br>" + dataServer.getAddr() + ":" + dataServer.getPort() +"</sub>"); %> </td> <td bgcolor="#D3D3D3"><% out.println("<sub><A href="showDeviceList.jsp"><b>MonitoredDevice</b></A>:<br>" + device.getHostname() + "</sub>"); %> </td></table><br><br><br><br><center> <fieldset style="width: 500px;"> <form name="RrdListForm" action="RrdListForm" method="POST"> <center> <label><b>Rrd Files for MonitoredDevice</b></label><br><br><br> </center> <% try { java.util.LinkedList<String> rrdDeviceList = dataClient.getRrdDeviceList(dataServer, device); out.println("<select name="rrdSelect" style="width: 200px;">"); String fileName = null; for (String rrd : rrdDeviceList){ fileName = rrd.substring(rrd.lastIndexOf("/") + 1); out.println("<option value="" + rrd + "">" + fileName + "</option>"); }Paolo Vanacore 566/1539 Pagina 273 di 279
    • out.println("</select>"); } catch (Exception ex){throw new Exception("Errore durante il recupero della lista deglirrd.nnDetails:n" + ex); } %> <button type="submit"> submit </button><br> <sub> Show Rrd Details<input type="radio" name="action" value="showRrdDetails"checked="checked"/> </sub> <br> </form> <br><br> <form> </form> </fieldset></center><br><br><br><br><jsp:include page="footer.jsp" flush="true"/> 7.4.19 Files di configurazione dellinterfaccia WiStatAdminweb.xml<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:javaee="http://java.sun.com/xml/ns/javaee"xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID"version="2.5"> <login-config> <auth-method>FORM</auth-method> <realm-name>Authentication Request</realm-name> <form-login-config> <form-login-page>/login.jsp</form-login-page> <form-error-page>/loginResponse</form-error-page> </form-login-config> </login-config> <security-role> <javaee:description>Admin</javaee:description> <javaee:role-name>adminLogin</javaee:role-name> </security-role> <security-constraint> <web-resource-collection> <web-resource-name>Reserved Area</web-resource-name> <url-pattern>/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>adminLogin</role-name> </auth-constraint> </security-constraint>Paolo Vanacore 566/1539 Pagina 274 di 279
    • <javaee:display-name>WiStatAdmin</javaee:display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <error-page> <exception-type>java.lang.Exception</exception-type> <location>/ErrorPage.jsp</location> </error-page> <servlet> <javaee:description></javaee:description> <javaee:display-name>NewDataServerForm</javaee:display-name> <servlet-name>NewDataServerForm</servlet-name> <servlet-class>controller.NewDataServerForm</servlet-class> </servlet> <servlet-mapping> <servlet-name>NewDataServerForm</servlet-name> <url-pattern>/NewDataServerForm</url-pattern> </servlet-mapping> <servlet> <javaee:description></javaee:description> <javaee:display-name>DataServerListForm</javaee:display-name> <servlet-name>DataServerListForm</servlet-name> <servlet-class>controller.DataServerListForm</servlet-class> </servlet> <servlet-mapping> <servlet-name>DataServerListForm</servlet-name> <url-pattern>/DataServerListForm</url-pattern> </servlet-mapping> <servlet> <javaee:description></javaee:description> <javaee:display-name>DataClientForm</javaee:display-name> <servlet-name>DataClientForm</servlet-name> <servlet-class>controller.DataClientForm</servlet-class> </servlet> <servlet-mapping> <servlet-name>DataClientForm</servlet-name> <url-pattern>/DataClientForm</url-pattern> </servlet-mapping> <servlet> <javaee:description></javaee:description> <javaee:display-name>DeviceListForm</javaee:display-name> <servlet-name>DeviceListForm</servlet-name> <servlet-class>controller.DeviceListForm</servlet-class> </servlet> <servlet-mapping> <servlet-name>DeviceListForm</servlet-name> <url-pattern>/DeviceListForm</url-pattern> </servlet-mapping> <servlet> <javaee:description></javaee:description> <javaee:display-name>RrdListForm</javaee:display-name> <servlet-name>RrdListForm</servlet-name> <servlet-class>controller.RrdListForm</servlet-class> </servlet>Paolo Vanacore 566/1539 Pagina 275 di 279
    • <servlet-mapping> <servlet-name>RrdListForm</servlet-name> <url-pattern>/RrdListForm</url-pattern> </servlet-mapping> <servlet> <javaee:description></javaee:description> <javaee:display-name>LogoutForm</javaee:display-name> <servlet-name>LogoutForm</servlet-name> <servlet-class>controller.LogoutForm</servlet-class> </servlet> <servlet-mapping> <servlet-name>LogoutForm</servlet-name> <url-pattern>/LogoutForm</url-pattern> </servlet-mapping> <javaee:description></javaee:description> <servlet> <javaee:description></javaee:description> <javaee:display-name>RrdDetailsForm</javaee:display-name> <servlet-name>RrdDetailsForm</servlet-name> <servlet-class>controller.RrdDetailsForm</servlet-class> </servlet> <servlet-mapping> <servlet-name>RrdDetailsForm</servlet-name> <url-pattern>/RrdDetailsForm</url-pattern> </servlet-mapping> <servlet> <javaee:description></javaee:description> <javaee:display-name>AddMonitorForm</javaee:display-name> <servlet-name>AddMonitorForm</servlet-name> <servlet-class>controller.AddMonitorForm</servlet-class> </servlet> <servlet-mapping> <servlet-name>AddMonitorForm</servlet-name> <url-pattern>/AddMonitorForm</url-pattern> </servlet-mapping> <servlet> <javaee:description></javaee:description> <javaee:display-name>loginResponse</javaee:display-name> <servlet-name>loginResponse</servlet-name> <servlet-class>controller.loginResponse</servlet-class> </servlet> <servlet-mapping> <servlet-name>loginResponse</servlet-name> <url-pattern>/loginResponse</url-pattern> </servlet-mapping> <servlet> <javaee:description></javaee:description> <javaee:display-name>MonitorsForm</javaee:display-name> <servlet-name>MonitorsForm</servlet-name> <servlet-class>controller.MonitorsForm</servlet-class> </servlet> <servlet-mapping> <servlet-name>MonitorsForm</servlet-name> <url-pattern>/MonitorsForm</url-pattern> </servlet-mapping> <servlet> <javaee:description></javaee:description> <javaee:display-name>ReportListForm</javaee:display-name> <servlet-name>ReportListForm</servlet-name>Paolo Vanacore 566/1539 Pagina 276 di 279
    • <servlet-class>controller.ReportListForm</servlet-class> </servlet> <servlet-mapping> <servlet-name>ReportListForm</servlet-name> <url-pattern>/ReportListForm</url-pattern> </servlet-mapping> <servlet> <javaee:description></javaee:description> <javaee:display-name>NewReportForm</javaee:display-name> <servlet-name>NewReportForm</servlet-name> <servlet-class>controller.NewReportForm</servlet-class> </servlet> <servlet-mapping> <servlet-name>NewReportForm</servlet-name> <url-pattern>/NewReportForm</url-pattern> </servlet-mapping> <servlet> <javaee:description></javaee:description> <javaee:display-name>GenericRrdFileForm</javaee:display-name> <servlet-name>GenericRrdFileForm</servlet-name> <servlet-class>controller.GenericRrdFileForm</servlet-class> </servlet> <servlet-mapping> <servlet-name>GenericRrdFileForm</servlet-name> <url-pattern>/GenericRrdFileForm</url-pattern> </servlet-mapping></web-app>Paolo Vanacore 566/1539 Pagina 277 di 279
    • 8 Bibliografia e Sitografia [1] Andrew S. Tenenbaum – Computer Networks – Prentice Hall, IV ed. [2] Ruggiero Adinolfi – Reti di computer – McGraw-Hill, II ed. [3] Maunali Cisco degli apparati di rete – www.cisco.com [4] Douglas R.Mauro & Kevin J. Schmidt – Essential SNMP – OReilly, II ed. [5] RFC1157 – Simple Network Management Protocol (SNMP) [6] RFC1901 – Introduction to Community-based SNMPv2 [7] RFC2570 – Introduction to Version 3 of the Internet-standard [8] Cacti Manual – http://www.cacti.net/downloads/docs/html/ [9] RRDTool Documentation – http://oss.oetiker.ch/rrdtool/doc/index.en.html [10] Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, Clifford Stein – Introduzione agli algoritmi e strutture dati – McGraw-Hill, II ed. [11] Martin Fowler – UML Distilled. A brief guide to the standard object modelling language – Addison-Wesley, III ed. [12] Ian Sommerville – Software Engineering – Addison-Wesley, VIII ed. [13] Bruce Eckel – Thinking in Java – vol. 1, 2, 3 – Pearson Education, IV ed [14] Cay S. Horstmann, Gary Cornell – Core Java 2 – vol. 1, 2 – Pearson Education, VII ed. [15] Cay S. Horstmann – Progettazione del software e Design Pattern in Java – Apogeo [16] Java Std Ed. 6 API Documentation – http://java.sun.com/javase/6/docs/ [17] Anders Moller, Michael Schwartzbach – Introduzione a XML – Pearson Education [18] W3C recommendations – www.w3.orgPaolo Vanacore 566/1539 Pagina 278 di 279
    • [19] Sheldon M.Ross – Probabilità e statistica per lingegneria e le scienze – Apogeo, II ed. [20] R.Giuliano – Elementi di calcolo delle probabilità e statistica – Edizioni ETS [21] Apache Tomcat 6 documentation – http://tomcat.apache.org/tomcat-6.0-doc/ [22] Jason Hunter with William Crawford – Java Servlet Programming – OReilly, II ed. [23] Phil Hanna – JSP, La guida completa – McGraw-Hill [24] The JFreeChart Class Library, Version 1.0.13, Developer Guide [25] JFreeChart Javadoc – http://www.jfree.org/jfreechart/api/javadoc/index.htmlPaolo Vanacore 566/1539 Pagina 279 di 279