UNIVERSITÀ DEGLI STUDI DI PARMA DIPARTIMENTO DI MATEMATICA E INFORMATICA Corso di Laurea in Informatica Tesi di Laurea Progettazione e Realizzazione di una Applicazione Android per l’Accesso a Learning Management System Relatore: Prof. Federico Bergenti Candidato: Bartolomeo Lombardi Anno Accademico 2014/2015 Ai miei genitori, Vito e Teresa. Alle mie sorelle, Mariagrazia e Giusy. Indice 1 Learning Management System 1.1 Introduzione . . . . . . . . . . . . . . 1.2 CampusNet . . . . . . . . . . . . . . 1.2.1 Introduzione . . . . . . . . . . 1.2.2 Sezioni di CampusNet . . . . 1.2.3 Caratteristiche . . . . . . . . 1.2.4 Autenticazione . . . . . . . . 1.3 EasyCourse . . . . . . . . . . . . . . 1.3.1 Introduzione . . . . . . . . . . 1.3.2 Motivi dell’utilizzo . . . . . . 1.3.3 Vantaggi . . . . . . . . . . . . 1.3.4 Integrazione . . . . . . . . . . 1.4 ESSE3 . . . . . . . . . . . . . . . . . 1.4.1 Introduzione . . . . . . . . . . 1.4.2 Scopo dell’utilizzo . . . . . . . 1.4.3 Integrazione con altri sistemi . 1.4.4 Vantaggi . . . . . . . . . . . . 1.4.5 Usabilità . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 5 6 6 6 8 9 10 10 10 11 13 14 14 14 16 17 17 2 Fonti Dati Utilizzate 2.1 Pagine di CampusNet . . . . . . 2.1.1 Avvisi e news . . . . . . 2.1.2 Docenti . . . . . . . . . 2.1.3 Corsi . . . . . . . . . . . 2.2 Pagine di ESSE3 . . . . . . . . 2.2.1 Bacheca Appelli d’esame 2.2.2 Carriera universitaria . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 18 18 21 23 25 25 28 . . . . . . . . . . . . . . . . . . . . . 3 Implementazione e Funzionamento 30 3.1 Strumenti utilizzati . . . . . . . . . . . . . . . . . . . . . . . . 30 3.1.1 Android SDK . . . . . . . . . . . . . . . . . . . . . . . 30 2 3.2 3.3 3.1.2 Android Studio . . . . . . . . . Libreria Jsoup . . . . . . . . . . . . . . 3.2.1 Introduzione . . . . . . . . . . . 3.2.2 Caricare documenti . . . . . . . 3.2.3 Estrazione e manipolazione dati Architettura dell’applicazione . . . . . 3.3.1 View . . . . . . . . . . . . . . . 3.3.2 Model . . . . . . . . . . . . . . 3.3.3 Controller . . . . . . . . . . . . Riferimenti bibliografici . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 33 33 33 35 41 42 54 66 70 3 Sommario L’obiettivo di questa tesi è di indagare la possibilità di realizzare un’applicazione Android in grado di accedere ad alcune informazioni contenute in alcuni LMS, attualmente il corso di informatica fa riferimento a tre piattaforme LMS. Quindi lo scopo principale è stato quello di studiare la struttura di ogni singola piattaforma e di implementare componenti in grado di ricavare informazioni da esse e gestirle nel miglior modo possibile. Le informazioni che si è scelto di rendere accessibili attraverso l’applicazione sono: avvisi, news, docenti, corsi, appelli e la propria carriera universitaria. Il lavoro di tesi è organizzato nel modo seguente: Il capitolo 1 introduce brevemente la nozione di Learning Management System e descrive più in dettaglio le piattaforme utilizzate dal corso di informatica. Il capitolo 2 descrive le pagine HTML che sono state utilizzate per acquisire informazioni riguardo le varie piattaforme. Il capitolo 3 descrive tutti i processi di sviluppo di ogni singola sezione dell’applicazione partendo dagli strumenti e le librerie utilizzate. Infine vi è spazio alle conclusioni e sviluppi futuri. 4 Capitolo 1 Learning Management System 1.1 Introduzione Con il termine Learning Management System LMS si identifica una piattaforma applicativa in grado di erogare informazioni e servizi, tipicamente usata per l’amministrazione di corsi di formazione e corsi di laurea. LMS presidia la distribuzione dei corsi on-line, l’iscrizione degli studenti, il tracciamento delle attività on-line. La maggior parte degli LMS sono strutturati in maniera tale da facilitarne, dovunque e in qualunque momento, l’accesso e la gestione dei contenuti, la maggior parte di questi sistemi tengono conto dello studente principiante, facilitandone l’auto-iscrizione e l’accesso ai corsi. Il motivo principale dell’uso è la capacità di erogare strumenti quali creazione, gestione, memorizzazione dei contenuti didattici, composizione e modularizzazione delle unità didattiche fondamentali, tracciamento e memorizzazione delle interazioni degli studenti. L’Università di Parma attualmente adopera tali sistemi per offrire dati relativi ai corsi di laurea. Il corso di studio di Informatica attualmente adopera tre LMS, ovvero CampusNet http://informatica.unipr.it/cgi-bin/campusnet/home.pl per informazioni relative al corso di studio, EasyCourse http://easycourse. unipr.it/Orario/CdS_in_Matematica_e_Informatica/2014-2015/index. html per gli orari delle lezioni e Esse3 https://unipr.esse3.cineca.it/ Home.do per la gestione amministrativa e carriera universitaria. 5 1.2 CampusNet 1.2 CampusNet 1.2.1 Introduzione Learning Management System CampusNet è una piattaforma informatica che consente di gestire in modo facile ed intuitivo tutti i servizi Web relativi ad uno o più percorsi formativi universitari. CampusNet mette a disposizione di studenti e docenti un ambiente Web altamente integrato al fine di facilitare e promuovere uno scambio diretto di informazioni. Attraverso CampusNet i docenti possono inserire tutte le informazioni relative ai propri corsi di insegnamento, inserire materiale didattico, gestire l’orario delle lezioni, pubblicare le date degli appelli, inserire i risultati degli esami, prenotare un’aula, mettere avvisi nella homepage, proporre argomenti di tesi, inviare email a gruppi di studenti, mantenere un proprio registro delle attività. Invece gli studenti, possono consultare le informazioni relative ai corsi, scaricare il materiale didattico, iscriversi online agli appelli, inserire annunci in bacheca, consultare l’agenda del docente, iscriversi ad attività proposte dal docente, ricevere per email informazioni riguardanti corsi, appelli ed altre attività. 1.2.2 Sezioni di CampusNet Si possono notare le varie sezioni del sito dal menu principale, in figura 1.1, che sono appunto i moduli base che mette a disposizione la piattaforma, ovvero: • Home viene descritto il corso di laurea e eventuali avvisi e news relativi ad uno specifico corso o docente. • Docenti contiene tutte le informazioni relative ai docenti: nome, indirizzo, contatti, ruolo, orario di ricevimento studenti e interessi. Ogni docente può modificare le proprie informazioni in qualsiasi momento. • Corsi gestisce i dati relativi ai corsi di insegnamento: nome del corso, tipologia, crediti, obiettivi formativi, programma, testi consigliati. É mantenuto dai singoli docenti che possono modificare solo i dati relativi ai propri corsi. • Orario Lezioni organizza l’orario delle lezioni dell’intero corso provvedendo alla prenotazione delle aule e fornisce strumenti per evitare sovrapposizioni di orario o di aula. Gli orari possono essere inseriti dai singoli docenti, dall’amministratore o dalla segreteria didattica. 6 1.2 CampusNet Learning Management System • Aule raccoglie le informazioni relative alle aule quali nome, capienza, strumenti disponibili e responsabile. Un sistema di mappe interattive che utilizza la Google Maps API https://developers.google.com/ maps/ permette una facile localizzazione dell’aula. A seconda delle esigenze le strutture didattiche possono o meno essere inserite nel calendario delle prenotazioni. Oltre alle singole informazioni è possibile effettuare prenotazioni degli spazi didattici, con possibilità di prenotazione per uno o più giorni, controllando automaticamente la disponibilità. Un sistema di ricerca permette di trovare un aula disponibile in modo semplice e veloce. • Appelli gestisce le date degli appelli, prenota l’aula e consente agli studenti di iscriversi online. Gli appelli possono essere inseriti dai docenti o dalla segreteria didattica. Il docente può inserire i risultati degli esami che verranno mostrati solo allo studente iscritto. Il docente può inviare email al gruppo di studenti iscritti ad un determinato appello. Un sistema automatico invia un promemoria al docente alcuni giorni prima dell’appello. Appelli imminenti vengono automaticamente visualizzati nella homepage. • Iscrizioni Esami consente agli studenti di iscriversi agli appelli d’esame. Studenti iscritti agli appelli possono ricevere comunicazioni email da parte del docente e consultare il risultato del loro esame. Figura 1.1: Homepage di CampusNet 7 1.2 CampusNet 1.2.3 Learning Management System Caratteristiche La caratteristica principale di CampusNet è senza dubbio l’estrema versatilità del software all’adeguarsi alle innumerevoli situazioni presenti nel panorama della didattica universitaria. Lo testimonia il fatto che CampusNet è in grado di gestire percorsi formativi di facoltà letterarie, mediche e scientifiche e soddisfare le esigenze di diversi atenei. Le principali caratteristiche sono: • Pagine Web create in modo dinamico a partire da informazioni inserite direttamente dai docenti e dagli studenti. • Informazioni non ridondanti, tutti i database sono interconnessi tra loro in modo da permettere lo scambio di informazioni e facilitare l’aggiornamento dei contenuti. • Grafica omogenea e facilmente personalizzabile senza intervenire sul codice. • Amministrazione tramite Web browser. • L’amministratore di un’istanza ha la possibilità di cambiare aspetto e contenuti di tutte le pagine del sito da lui gestito. • Pagine conformi ai requisiti della legge sull’accessibilità, inoltre è previsto un foglio di stile adatto per la navigazione da parte di persone ipovedenti. • Protezione dei dati, infatti tutte le informazioni sono modificabili dall’utente che le ha inserite o dall’amministratore dell’istanza. • Tutti i contenuti possono essere facilmente esportati in formati tabulari, CSV, XML, JSON. • Tutte le form di inserimento dati si basano su uno schema comune al fine di facilitare l’utilizzo da parte di docenti e studenti. • Utilizzo della Google maps API per la creazione di mappe interattive utili per localizzare strutture, aule, laboratori. • I siti di CampusNet prevedono l’uso di AJAX per creare pagine con contenuti ottenuti in modo asincrono mediante XMLHttpRequest. 8 1.2 CampusNet 1.2.4 Learning Management System Autenticazione Per accedere a risorse private come materiale didattico o iscrizione agli esami, CampusNet prevede un’autenticazione; esistono quattro tipologie di utenti che possono accedere: • Guest • Studenti • Docenti • Ammministratore L’autenticazione degli studenti e dei docenti avviene o mediante server remoto LDAP o accesso federato CAS, quindi le credenziali sono le stesse per l’accesso alla Web mail. La piattaforma consiste di trenta database relazionali gestiti dal kernel WODA (Web-Oriented-Database) attraverso dei file di definizione scritti in Perl. L’architettura di CampusNet garantisce un’elevata velocità di esecuzione e questo rende facilmente la navigabilità con qualsiasi tipo di connessione. La grafica risulta accessibile con qualsiasi tipo di browser. La struttura modulare del software permette una facile integrazione di CampusNet con altri servizi Web. CampusNet facilita notevolmente anche il lavoro del Webmaster mettendo a disposizione una serie di strumenti avanzati per l’amministrazione del sito, la creazione di pagine Web e la gestione dei contenuti. Tutte le operazioni di amministrazione vengono interamente svolte attraverso Web browser. 9 1.3 EasyCourse 1.3 EasyCourse 1.3.1 Introduzione Learning Management System La seconda piattaforma utilizzata è EasyCourse http://easycourse.unipr. it/Orario/CdS_in_Matematica_e_Informatica/2014-2015/index.html, un sistema informatico per la gestione e la ottimizzazione degli orari delle lezioni. EasyCourse è capace di contemperare gli interessi di studenti e docenti, restituendo un orario delle lezioni ottimizzato in funzione degli spazi disponibili e dei vincoli inseriti dall’amministratore. 1.3.2 Motivi dell’utilizzo La scelta è ricaduta su EasyCourse in quanto la compilazione manuale degli orari produceva i seguenti problemi: • Procedimento di pianificazione degli orari delle lezioni lungo e macchinoso; • Assenza di un procedimento automatico di controllo; • Recupero difficoltoso delle richieste dei docenti; • Incastro laborioso delle lezioni dello studente; • Aule sovraffollate; • Errore umano. Dopo aver inserito tutti i vincoli e gli orari delle lezioni, l’algoritmo considera tutti i dati e rispetto alle disponibilità delle aule restituisce il calendario delle lezioni per ogni giorno della settimana. In figura 1.2 viene mostrata la pagina principale della piattaforma. 10 1.3 EasyCourse Learning Management System Figura 1.2: Homepage di EasyCourse 1.3.3 Vantaggi Il vantaggio principale della piattaforma è la possibilità di raccogliere dati in modo automatica, ovvero tutti i docenti accedono al proprio profilo online ed esprimono le loro disponibilità temporali. I docenti possono esprimere preferenze del tipo: • Fascia oraria; • Giorni allocabili; • Giorni di impossibilità; • Giorni di sgradevolezza; • Aule desiderate; • Aule indifferenti; • Aule non conforme; • Aule sgradite. 11 1.3 EasyCourse Learning Management System Il docente fuori sede potrà scegliere di fare lezione giorni consecutivi e la fascia oraria di inizio per il primo giorno e la fascia oraria di fine per l’ultimo giorno. Successivamente è compito dell’amministratore scegliere se accettare o modificare le preferenze desiderate dai docenti. Il secondo vantaggio di EasyCourse è rappresentato dal fatto che in fase di calcolo il software è in grado di prendere in considerazione regole inserite dall’amministratore, ciascuna regola ha un peso, infatti l’algoritmo lavora su un’insieme di regole ponderandole in funzione del suddetto peso. Ogni regola può essere impostata come vincolo, ossia irrinunciabile nell’elaborazione dell’orario, oppure come obiettivo al quale può essere attribuito un livello di importanza da 0 a 100. Una regola o un vincolo che riguardano le aule, i docenti, gli insegnamenti e le esigenze degli studenti vengono quindi prese in carico dall’algoritmo di ottimizzazione elaborandole ed ottenendo come risultato l’orario delle lezioni. Il terzo vantaggio di EasyCourse è poter revisionare manualmente l’orario in modo semplice attraverso pratiche funzioni di gestione e controlli automatici. Il livello di revisione degli orari prevede diverse funzionalità, per esempio è possibile visualizzare i conflitti per insegnamento di sovrapposizione, oppure le indisponibilità temporale dei docenti. L’ultimo vantaggio importante della piattaforma è dato dalla possibilità di pubblicare l’orario sul Web in modo automatico, in modo tale da renderlo accessibile agli studenti e ai docenti, figura 1.3. Gli orari sono visualizzabili e organizzati per categoria: specifici docenti, aule e percorso di studio. Cliccando su ogni cella è possibile visualizzare le informazioni del corso, per esempio: insegnamento, crediti, nome del docente, sede e capienza dell’aula. Mentre cliccando sul nome del docente è possibile visualizzare tutti i corsi da egli sostenuti. 12 1.3 EasyCourse Learning Management System Figura 1.3: Tabella orario lezione 1.3.4 Integrazione EasyCourse è completamente integrabile con sistemi informatici per la gestione dell’offerta didattica, come ESSE3 e SIADI http://www.cineca.it/it; è possibile accedere a tale piattaforma con le credenziali di Ateneo, poiché può comunicare con: LDAP, CAS, SHIBBOLETH; inoltre può gestire la prenotazione delle aule direttamente con: MRBS o EasyRoom. Una funzione utile per gli studenti è Umemo, ovvero la possibilità di ricevere notifiche delle lezioni tramite SMS. 13 1.4 ESSE3 1.4 1.4.1 Learning Management System ESSE3 Introduzione ESSE3 https://unipr.esse3.cineca.it/Home.do è il sistema informatico di gestione della Didattica che offre a studenti e docenti un’area riservata dove gestire le proprie iscrizioni agli esami, la pubblicazione degli appelli, la gestione dei voti, il pagamento delle tasse, la partecipazione ad iniziative organizzate dall’Ateneo, ecc. ESSE3 è un gestionale studenti per le segreterie universitarie (servizi e segreteria studenti) nato per la gestione della riforma universitaria italiana (D.M. 509) e per l’attuazione del Bologna Process in Italia. Permette di gestire la carriera dello studente e l’organizzazione dell’Ateneo con un unico sistema informativo, una base dati coerente e accessi Web per tutti gli utenti della didattica. 1.4.2 Scopo dell’utilizzo Lo scopo principale è quello di fornire allo stesso tempo sia le funzionalità rivolte all’amministrazione universitaria (segreteria studenti) per gestire tutto il percorso di attraversamento dello studente, sia i servizi Web a valore aggiunto rivolti al singolo studente. ESSE3 è quindi al tempo stesso in tutte le università che lo adottano il principale sistema di backoffice centrale ad uso non solo delle segreterie studenti ma anche degli uffici che si occupano di altri processi amministrativi legati alla gestione (presidenze, nuclei di valutazione, uffici tirocini e stage, uffici Erasmus, ecc..) e ma anche il sito Web di riferimento dei servizi studente in università spesso integrato con altri servizi del portale universitario o legati all’e-learning. Le funzioni principali di ESSE3 sono suddivise in diverse aree: • Area didattica: – Gestione dell’offerta didattica per il controllo carriere; – Gestione della carriera dello studente; – Esami di profitto e certificazione titolo; – Area Amministrativa; – Gestione ammissioni; – Gestione studente in ingresso e in uscita. • Area tasse: – Gestione tasse per studente; 14 1.4 ESSE3 Learning Management System – Configurazione e operazioni massive; – Gestione diritto allo studio; – Chiusure contabili per la ragioneria. • Area Post-Lauream: – Gestione Esame di Stato; – Gestione Scuole di Specializzazione; – Gestione Dottorati di Ricerca; – Gestione stage e tirocini professionalizzanti. Oltre a queste funzioni applicative il sistema fornisce alcuni servizi comuni, relativi a: • Amministrazione del sistema; • Funzioni di servizio; • Statistiche e Reportistica generale. É possibile notare in figura 1.4 le varie sezioni appena menzionate. Figura 1.4: Homepage di ESSE3 15 1.4 ESSE3 1.4.3 Learning Management System Integrazione con altri sistemi La Programmazione Didattica trasmette a ESSE3 oltre all’assetto globale dell’offerta formativa anche lo scadenzario del calendario accademico e la pianificazione degli appelli d’esame. L’attivazione del modulo Community consente, tramite un apposito gateway di comunicazione, l’integrazione con il mondo delle piattaforme e-learning, facilitando enormemente la gestione dell’iscrizione e dell’accesso ai corsi a distanza. Attraverso University Planner, arricchisce i propri servizi Web dei dati relativi agli orari delle lezioni e della possibilità di consultare la disponibilità delle risorse. L’integrazione di questo Modulo con U-GOV Risorse Umane garantisce l’allineamento della anagrafica dei docenti, con il dettaglio dei dati necessario. Fondamentale risulta anche l’integrazione con U-GOV Contabilità, legata a tutta l’area finanziaria e di gestione delle tasse. Per quanto riguarda i moduli di U-GOV Pianificazione e Controllo, sono già disponibili report standard di analisi sui flussi degli studenti e di monitoraggio delle performance degli stessi (esami di profitto, laurea, crediti acquisiti, etc). ESSE3 consente ovviamente integrazioni con altri sistemi esterni quali: • Sistemi MiUR: per tutti gli adempimenti necessari (Es: rilevazioni statistiche, Anagrafe Nazionale Studenti). • Banche ed enti tesorieri: il sistema gestisce il flusso finanziario dei dati relativi ai pagamenti con banche o enti convenzionati con l’Università, compresa la modalità di pagamento on line. • Enti Regionali per il diritto allo studio: gestisce il flusso di dati delgi studenti in uscita e in ingresso per determinare il criterio di assegnazione delle borse di studio. • Banche dati studenti laureati: Consorzio Almalurea e Vulcano. • Gestionali studenti CINECA di altre università: per quanto riguarda la gestione dei trasferimenti esiste un protocollo di scambio fra dati che facilità l’acquisizione/esportazione dei dati degli studenti trasferiti fra un Ateneo e l’altro; per la verifica di autocertificazioni presentate dagli studenti presso pubbliche amministrazioni è attivabile l’adesione a E3Network. • Sistemi per la gestione della mobilità internazionale: Move-on, Move-on net (prodotti del partner Unisolution). 16 1.4 ESSE3 1.4.4 Learning Management System Vantaggi ESSE3 dispone di un’area Web sia per l’accesso pubblico che per l’interazione diretta da parte di studente e docente, i principali attori della didattica, ma anche aziende e pubbliche amministrazioni. L’architettura permette una portabilità multi-piattaforma dell’interfaccia, consentendo anche l’uso di postazioni remote (totem) e device portatili. Il servizio si configura come un vero e proprio portale della didattica che si compone di un’area pubblica, sulla quale ogni utente può liberamente consultare informazioni relative all’offerta didattica dell’Ateneo, ai test di ingresso di ammissione, agli appelli e alle sessioni di laurea. Dall’area pubblica ogni utente può effettuare una registrazione al portale, che dal punto di vista del sistema, significa prendere in carico una nuova persona nella fase di prescrizione-orientamento all’Ateneo. Dall’area registrato, il futuro studente può iscriversi ad un test di ammissione o immatricolarsi, iniziando l’iter della carriera come studente effettivo. Una volta immatricolato, dall’area riservata studente, si può accedere alle funzionalità caratteristiche della gestione ordinaria del proprio iter universitario, sia dal punto di vista amministrativo che dal punto di vista didattico (pagamento tasse, iscrizione, piano di studi, prenotazione esami, ecc..). Parallelamente anche il docente o in generale chi ha una parte nella gestione della didattica ha un accesso privilegiato alla gestione della propria attività. Esiste dunque un’area docente, riservata ai docenti titolari e/o ai loro collaboratori, da dove compilare il syllabus, il registro delle proprie attività, e verbalizzare gli esami - anche con firma digitale. 1.4.5 Usabilità Il modulo offre un’interfaccia client per le funzionalità di back-office (rivolta essenzialmente al personale amministrativo interno) e un interfaccia Web per gli attori principali della didattica (studenti e docenti). Entrambe sono ampiamente customizzabili secondo le esigenze organizzative dell’Ateneo e progettate secondo i criteri documentati di usabilità e accessibilità. Le funzionalità gestionali di back office si avvalgono anche di strumenti per l’organizzazione del lavoro (task manager), per rendere più immediato l’utilizzo del software e ottimizzare la distribuzione del carico. Automatismi configurabili consentono anche la generazione automatica di alcuni task, sulla base del workflow impostato nel sistema. 17 Capitolo 2 Fonti Dati Utilizzate In questo capitolo verranno descritte le pagine HTML che sono state utilizzate per acquisire informazioni riguardo le varie piattaforme. Le informazioni sono poi state usate per l’implementazione di alcune sezioni dell’applicazione, che verranno descritte poi nel capitolo seguente. 2.1 2.1.1 Pagine di CampusNet Avvisi e news Nella homepage di CampusNet è possibile notare una tabella contenente gli avvisi importanti del corso di laurea, come: comunicazioni relative al corso, esiti degli esami o modifiche relative agli orari di lezione. Ogni avviso è identificato dal titolo e dal docente che lo ha creato e cliccando su questo si viene reindirizzati alla pagina contenente la descrizione completa dell’avviso con ulteriori precisazioni. Figura 2.1: Elenco degli avvisi in CampusNet 18 2.1 Pagine di CampusNet Fonti Dati Utilizzate La figura 2.1 riporta un esempio di avvisi probabili della homepage di CampusNet. Volendo ottenere informazioni in modo dinamico, si è scelto di ricavare tali dati attraverso la lettura della pagina sorgente HTML, inoltre tale tecnica è stata utilizzata per tutte le pagine delle piattaforme, descritte in questo capitolo. Prendendo il primo avviso come riferimento, possiamo notare l’HTML, generato dalla piattaforma. <DIV C L A S S = H O M E - A V V I S I _ D C > <TABLE C L A S S = A V V I S I - F O R M A T - 3 BORDER=0 CELLSPACING=2 CELLPADDING=2 WIDTH= " 100 " > <TH C L A S S = A V V I S I - F O R M A T - 3 ALIGN=LEFT COLSPAN=2 > <B > Avvisi </B > </TH > <TD C L A S S = A V V I S I - F O R M A T - 3 > <TR > <A HREF= " http: // i n f o r m a t i c a . u n i p r . i t / cgi-bin / campusnet / avvisi.pl / Show ? _ i d = 9 a 9 a ; s o r t = U 1 ; s e a r c h = %7 btipologia %7 d %20%21%7 e %20 m %2 fprimopiano %2 fi %20 and %20%7 bdata %7 d %20 ge %20%272015%2 f05 %2 f21 %27; hits=3 " > Recupero lezioni di Intelligenza Artificiale </A > <B R > Dott. Federico Bergenti </TD > </TR > ... </TABLE > </DIV > 19 2.1 Pagine di CampusNet Fonti Dati Utilizzate Le informazioni relative agli avvisi e alle news, sono racchiuse in una sezione della pagina web, separate dal resto delle aree della pagina, pertanto è risultato molto semplice focalizzarsi su questa porzione di codice in quanto caratterizzata dai tag <DIV> . . . </DIV>. Lo scopo dei DIV è quello di fungere da semplici contenitori il cui aspetto, dimensione, posizione e funzione sono definiti, dal designer della pagina web. Gli avvisi vengono strutturati all’interno di una tabella, infatti ogni avviso/news è racchiuso dal tag <TR>. . . </TR> il quale identifica ogni singola riga della tabella. Nel <DIV> in questione è assegnato un attributo classe, questo ha permesso di accedere alle informazioni della sezione. Il metodo usato per l’estrapolazione dei dati verrà descritto nel capitolo seguente. Le informazioni raccolte per identificare ogni singolo avviso/news sono: • Titolo: posto sempre nel tag <A>. . . </A> infatti nell’avviso in questione possiamo rilevare il titolo dalla seguente riga: <A Recupero lezioni di Intelligenza Artificiale</A>; • Link: posto sempre come attributo HREF del tag <A HREF=link>; • Autore: posto tra il tag <BR> e </TD>. 20 2.1 Pagine di CampusNet 2.1.2 Fonti Dati Utilizzate Docenti Nella sezione docenti della piattaforma è possibile ottenere la lista di tutti i docenti che fanno parte del corso di laurea di informatica. Cliccando su ognuno di essi è possibile avere ulteriori precisazioni come: nome, indirizzo, contatti, ruolo, orario di ricevimento studenti e interessi. La figura 2.2 ripropone la pagina in descrizione. Figura 2.2: Elenco dei docenti 21 2.1 Pagine di CampusNet Fonti Dati Utilizzate Analizzando il sorgente della pagina in figura 2.2, è possibile notare che la lista dei docenti è strutturata in una tabella, ogni riga a sua volta è caratterizzata da: un’immagine, il nome completo del docente e la mail. <DIV ID= " searchFromTo " C L AS S = SE A R CH - F R OM T O > <H3 > Da 1 a 17 di 17 < / H3 > </DIV > <TABLE C L A S S = D O C E N T I - F O R M A T - D E F A U L T BORDER=0 CELLSPACING=2 CELLPADDING=2 WIDHT= " 100 " > ... <TR > <TD > <A HREF= " / cgi-bin / campusnet / docenti.pl / Show ? _id=bergenti;sort=DEFAULT;search=;hits=17 " style= " color: #000000; t e x t - d e c o r a t i o n : n o n e ; " > <B > Bergenti Dott. Federico </B > </A > </TD > </TR > ... </TABLE > </DIV > Questa porzione di codice mostra una singola riga della tabella, notiamo appunto che il tutto è contenuto in un <DIV>, dove all’interno viene stanziata la tabella contenente tutti i docenti del corso di laurea. La tabella ha come attributo CLASS=DOCENTI-FORMAT-DEFAULT, questo ha permesso al parse di focalizzarsi solamente sulle informazioni contenute tra i tag <TABLE> . . . </TABLE>. I dati utili per identificare ogni singolo docente sono: • Nome: posto sempre nel tag <B>. . . </B>; • Link: posto sempre come attributo HREF del tag <A HREF=link>. 22 2.1 Pagine di CampusNet 2.1.3 Fonti Dati Utilizzate Corsi Nella sezione corsi di CampusNet vengono gestiti tutti i dati relativi ai corsi di insegnamento disponibili per il corso di laurea di informatica. Per ogni insegnamento è possibile visualizzare: nome, tipologia, crediti, obiettivi formativi, programma, testi consigliati, ecc. La figura 2.3 riporta i primi tre corsi disponibili. Figura 2.3: Elenco di alcuni corsi di CampusNet Analizzando il sorgente della pagina in figura 2.3, è possibile notare che la lista dei corsi è strutturata in una tabella, ogni riga a sua volta è caratterizzata da un’ulteriore tabella che specifica il singolo corso e contiene: un’immagine, il nome completo del corso, anno accademico, classe del corso di studi e docente. <DIV ID= " searchFromTo " C L AS S = SE A R CH - F R OM T O > <H3 > Da 1 a 26 di 26 < / H3 > </DIV > <TABLE C L A S S = C O R S I - F O R M A T - D E F A U L T BORDER=0 CELLSPACING=0 CELLPADDING=1 width= " 100% " > <TR > <TD C L A S S = C O R S I - F O R M A T - D E F A U L T WIDTH= " 99% " VALIGN=TOP > <TABLE BORDER=0 CELLSPACING=1 CELLPADDING=1 width= " 100% " > <TR > <TD C L A S S = C O R S I - F O R M A T - D E F A U L T > <A HREF= " / cgi-bin / campusnet / corsi.pl / Show ? _ i d = e a d 6 ; s o r t = D E F A U L T ; s e a r c h = %20%7 baa %7 d %20%3 d %3 d %20%222014%2 d2015 %22%20; hits=26 " > <B > Algebra e Geometria </B > </A > </TD > </TR > <TR > <TD C L A S S = C O R S I - F O R M A T - D E F A U L T > Anno accademico: 2014/2015 </TD > </TR > <TR > <TD C L A S S = C O R S I - F O R M A T - D E F A U L T > Corso di studi in: L31 Informatica </TD > </TR > 23 2.1 Pagine di CampusNet Fonti Dati Utilizzate <TR > <TD C L A S S = C O R S I - F O R M A T - D E F A U L T > Docente: <A HREF= " / cgi-bin / campusnet / docenti.pl / Show ? _id=alessandrini " onmouseover= " ShowContactInfo ( ’ alessandrini ’) " onmouseout= " UnTip () " > Prof. Lucia Alessandrini </A > </TABLE > ... </TABLE > </DIV > Anche in questo caso i dati sono ben strutturati secondo una tabella principale contenente tante sotto tabelle quante il numero di corsi disponibili sulla pagina. Nell’esempio in questione possiamo notare la tabella principale avente come attributo CLASS=CORSI-FORMAT-DEFAULT e una sotto tabella composta da quattro righe, formate da: • Nome del corso: contenuto nella prima riga posto tra i tag <B> . . . </B>; • Anno accademico: seconda riga, quindi tra i tag <TR> . . . </TR> che identificano la creazione di una nuova riga; • Corso di appartenenza: anch’esso posto tra i tag <TR> . . . </TR> come terza riga; • Docente: come ultima riga della tabella posto tra i tag <A> . . . </A>. Quindi presi in sequenza queste informazioni, poiché fisse per ogni singolo corso, si è riusciti a creare un oggetto con appunto quattro attributi per contenere i singoli dati per ogni corso. 24 2.2 Pagine di ESSE3 2.2 2.2.1 Fonti Dati Utilizzate Pagine di ESSE3 Bacheca Appelli d’esame La bacheca appelli d’esame su ESSE3 consente di accedere in sola consultazione alle informazioni sugli appelli d’esame disponibili per tutte i corsi di studio dell’Università di Parma, infatti prima di avviare la ricerca è indispensabile impostare il dipartimento e il corso di studio di appartenenza. La figura 2.4 mostra alcuni degli appelli del dipartimento di matematica e informatica per il corso di studio di informatica. Figura 2.4: Elenco di alcuni appelli di ESSE3 Le informazioni risultanti dalla ricerca sono: • Nome appello; • Periodo iscrizioni; • Data e ora della prova; • Tipo appello che può essere scritto o orale; • Tipo prova poiché una prova può essere finale o parziale; • Docenti che fanno parte della commissione; • Numero iscritti all’appello. Esaminando il sorgente della pagina Web in figura 2.4 possiamo notare la struttura scelta dalla piattaforma per organizzare i tali dati. 25 2.2 Pagine di ESSE3 Fonti Dati Utilizzate <TD ID= " " WIDTH= " " VALIGN= " TOP " COLSPAN= " " STYLE= " " ROWSPAN= " " CLASS= " DETAIL_TABLE " > [06149] INTELLIGENZA ARTIFICIALE </TD > <TD ID= " " WIDTH= " " VALIGN= " TOP " COLSPAN= " " STYLE= " T EXT -A LI GN :C EN TE R; " ROWSPAN= " " CLASS= " DETAIL_TABLE "> 02/06/2015 - 14/06/2015 </TD > <TD ID= " " WIDTH= " " VALIGN= " TOP " COLSPAN= " " STYLE= " T EXT -A LI GN :C EN TE R; " ROWSPAN= " " CLASS= " DETAIL_TABLE "> <A CLASS= " DETAIL_TABLE " TITLE= " " HREF= " DETTAGLIOTURNOOFFERTA.DO "> 17/06/2015 - 09:00 </A > </TD > <TD ID= " " WIDTH= " " VALIGN= " TOP " COLSPAN= " " STYLE= " " ROWSPAN= " " CLASS= " DETAIL_TABLE " > SCRITTO </TD > <TD ID= " " WIDTH= " " VALIGN= " " COLSPAN= " " STYLE= " " ROWSPAN= " " CLASS= " DETAIL_TABLE " > PROVA FINALE </TD > <TD ID= " " WIDTH= " " VALIGN= " " COLSPAN= " " STYLE= " " ROWSPAN= " " CLASS= " DETAIL_TABLE " > <TABLE BORDER= " 0 " CELLSPACING= " 0 " CELLPADDING= " 0 " > <TR CLASS= " DETAIL_TABLE " > <TD VALIGN= " TOP " > BERGENTI FEDERICO </TD > </TR > <TR CLASS= " DETAIL_TABLE " > <TD VALIGN= " TOP " > DAL PALU ’ ALESSANDRO </TD > </TR > </TABLE > </TD > <TD ID= " " WIDTH= " " VALIGN= " TOP " COLSPAN= " " STYLE= " T EXT -A LI GN :C EN TE R; " ROWSPAN= " " CLASS= " DETAIL_TABLE "> 0 </TD > </TR > Si può notare dal frammento di codice la diversità della composizione scelta da ESSE3 rispetto le altre piattaforme, per esempio CampusNet mette a disposizione la singola struttura che per la maggior parte delle volte è una tabella contenuta in un <DIV> separatore, con un singolo attributo CLASS per identificare un gruppo particolare di elementi. Mentre ESSE3 26 2.2 Pagine di ESSE3 Fonti Dati Utilizzate contiene tutti gli appelli disponibili in una singola tabella dove per ogni riga vengono incolonnate le informazioni precedentemente descritte riguardante il singolo appello. Infatti possiamo notare i dati importanti posti tra i tag <TD> . . . </TD> tutti avente un attributo CLASS=DETAIL_TABLE per specificare il gruppo e le proprietà che gli elementi devono avere. Grazie all’attributo CLASS siamo riusciti ad ottenere l’insieme delle informazioni per ogni singola riga che identifica il singolo appello, prendendo come esempio la parte di codice descritta precedentemente, le informazioni chiave sono: • Nome appello posto come prima colonna quindi tra i tag <TD> . . . </TD>; • Periodo iscrizione posto in seconda colonna tra i tag <TD> . . . </TD>; • Data e ora posto come terza colonna tra i tag <A> . . . </A>; • Tipo appello posto come quarta colonna tra i tag <TD> . . . </TD>; • Tipo prova posto come quinta colonna tra i tag <TD> . . . </TD>; • Docenti posto nella sotto tabella tra i tag <TD>. . . </TD>; • Numero iscritti posto come ultima colonna tra i tag <TD> . . . </TD> della tabella principale. Presi questi dati in sequenza si è riusciti a costruire un oggetto appello per poterlo utilizzare poi nell’applicazione in modo da costruire lo stesso elenco degli appelli. 27 2.2 Pagine di ESSE3 2.2.2 Fonti Dati Utilizzate Carriera universitaria Tramite la piattaforma ESSE3 è possibile visualizzare la propria carriera universitaria, l’elenco completo degli esami sostenuti che sono stati registrati in segreteria, con il voto, la data e i CFU acquisiti, ma questo solo dopo aver fatto l’accesso utilizzando le proprie credenziali di ateneo. La figura 2.5 mostra alcuni dei miei esami sostenuti. Figura 2.5: Elenco di alcuni esami di ESSE3 Esaminando la figura, si può notare che la lista degli esami sostenuti è costituita da una tabella, dove a ogni riga corrisponde un singolo esame ed è caratterizzata da: • Anno di corso; • Codice e nome dell’insegnamento; • Peso in CFU; • Stato dell’esame (frequentato o sostenuto); • Anno di frequenza; • Voto e data di verbalizzazione. La parte di codice che verrà riportata identifica la riga dell’esame di analisi matematica, questo per poter studiare la struttura scelta dalla piattaforma per la esposizione dei dati. Come si può notare segue le stesse line guida della pagina bacheca degli appelli d’esame descritta nella sezione 2.2.1 di questo capitolo. Infatti la disposizione è identica, una singola tabella contenente la lista degli esami sostenuti, in ogni riga viene descritto un singolo esame con le caratteristiche appena descritte. 28 2.2 Pagine di ESSE3 Fonti Dati Utilizzate <TR > <TD ID= " " WIDTH= " " VALIGN= " CENTER " COLSPAN= " " STYLE= " T EXT -A LI GN :C EN TE R; " ROWSPAN= " " CLASS= " DETAIL_TABLE "> 1 </TD > <TD ID= " " WIDTH= " " VALIGN= " CENTER " COLSPAN= " " STYLE= " BORDER-RIGHT: 0 PX NONE TRASPARENT; " ROWSPAN= " " CLASS= " D ET A I L_ T A BL E _ MI D D LE " > <A HREF= " AUTH / STUDENTE / LIBRETTO / L I B R ET T O AD S C EL T A .D O ? ADSCE_ID=7160219 & AMP;LREG_ID= " > 00013 - ANALISI MATEMATICA </A > </TD > <TD ID= " " WIDTH= " " VALIGN= " CENTER " COLSPAN= " " STYLE= " T EXT -A LI GN :C EN TE R; " ROWSPAN= " " CLASS= " DETAIL_TABLE "> 9 </TD > <TD ID= " " WIDTH= " " VALIGN= " CENTER " COLSPAN= " " STYLE= " T EXT -A LI GN :C EN TE R; " ROWSPAN= " " CLASS= " DETAIL_TABLE "> 2011/2012 </TD > <TD ID= " " WIDTH= " " VALIGN= " CENTER " COLSPAN= " " STYLE= " T EXT -A LI GN :C EN TE R; " ROWSPAN= " " CLASS= " DETAIL_TABLE "> 28& NBSP;- & NBSP;23 /07/2013 </TD > </TR > Il codice riportato mostra il contenuto della riga che identifica l’esame di analisi matematica all’interno della tabella, infatti possiamo notare le caratteristiche poste tra i tag <TD> . . . </TD>. Seguendo il codice in modo sequenziale troviamo: l’anno del corso, nome dell’insegnamento, CFU dell’esame, l’anno di frequenza e il voto e la data di verbalizzazione. Avendo questa struttura fissa è risultato molto semplice estrapolare e salvare queste informazioni dalla pagina per poi poterle utilizzare nell’applicazione sviluppata descritta nel capitolo seguente. 29 Capitolo 3 Implementazione e Funzionamento In questo capitolo verranno descritti tutti i processi per lo sviluppo di ogni singola sezione dell’applicazione partendo dagli strumenti e le librerie utilizzate. 3.1 Strumenti utilizzati Prima di entrare nei dettagli implementativi è bene mostrare i componenti necessari per lo sviluppo dell’applicazione. 3.1.1 Android SDK Android SDK (Software Development Kit) è un pacchetto di sviluppo per applicazioni che contiene un set completo di API (Application Programming Interface), librerie e strumenti di sviluppo utili a compilare, testare e debuggare applicazioni per Android. I linguaggi di programmazione alla base della maggior parte delle applicazioni studiate per Android sono Java e C/C++. Con l’SDK, scaricabile dal sito ufficiale https://developer.android.com/ sdk/index.html, sarà quindi possibile disporre sul proprio PC di un’interfaccia in grado di lanciare e modificare le applicazioni Android. É anche possibile ottenere i driver necessari per interfacciare il nostro dispositivo al pc, per poter compilare ed eseguire l’applicazione direttamente sullo smartphone senza dover usare l’emulatore dell’SDK. 30 3.1 Strumenti utilizzati 3.1.2 Implementazione e Funzionamento Android Studio Android Studio è l’ambiente di sviluppo integrato ufficiale firmato Google, basato su IntelliJ IDEA https://www.jetbrains.com/idea/, per sviluppare su piattaforma Android, liberamente disponibile per Windows, Mac OS X e Linux, sotto licenza Apache 2.0 al sito https://developer.android. com/sdk/index.html. Un editor intelligente capace di offrire: completamento avanzato del codice, refactoring, e analisi; grazie a queste caratteristiche rendono lo sviluppatore più produttivo e veloce nel completamento dell’applicazione. La figura 3.1 mostra la schermata di progettazione di Android Studio. Figura 3.1: Schermata di sviluppo di Android Studio Una delle caratteristiche principali è la possibilità di avviare nuovi progetti utilizzando template messi a disposizione da Android Studio. Inoltre è possibile configurarlo con GitHub https://github.com/ in modo da importare codice dal canale di Google oppure esportare e rendere pubblico il proprio progetto. Con Android Studio risulta molto semplice sviluppare applicazioni multi-schermo (smartphone Android, tablet, Android Wear, TV Android, Android Auto e Google Glass) poiché è integrato un modulo capace di facilitare la gestione delle risorse e delle risoluzioni come si può notare dalla figura 3.2. Infatti ad ogni esecuzione/debug dell’applicazione è possibile scegliere il profilo del dispositivo Android da emulare tra quelli più comuni. 31 3.1 Strumenti utilizzati Implementazione e Funzionamento Figura 3.2: Multi-schermo Android Studio Uno dei punti di forza di Android Studio è la possibilità di creare APK multipli dell’applicazione con caratteristiche magari differenti specificate nel file build.gradle del progetto. Entrando nel dettaglio Gradle è un software per l’automazione dello sviluppo fondato sulle idee di Apache Ant e Apache Maven, che introduce un Domain-Specific Language (DSL) basato su Groovy, al posto della più tradizionale modalità XML usata per dichiarare la configurazione del progetto. Gradle https://gradle.org/ getting-started-android/ è stato progettato per sviluppi multi-progetto che possono crescere fino a divenire abbastanza grandi e supporta sviluppi incrementali determinando in modo intelligente quali parti del build tree sono aggiornate (up-to-date), in modo che tutti i processi che dipendono solo da quelle parti non avranno bisogno di essere ri-eseguiti; così facendo, il software riduce significativamente il tempo di costruzione del progetto, in quanto, durante il nuovo tentativo di costruzione, verranno eseguite solo le attività il cui codice è effettivamente stato alterato a partire dall’ultima costruzione completata. Gradle supporta anche la costruzione del progetto per processi concorrenti, il che consente di svolgere alcuni compiti durante la costruzione (ad esempio, i test automatizzati attraverso gli unit test), eseguiti in parallelo su più core della medesima CPU, su più CPU o su più computer. 32 3.2 Libreria Jsoup 3.2 3.2.1 Implementazione e Funzionamento Libreria Jsoup Introduzione Jsoup http://jsoup.org/ è una potente libreria Java di parsing HTML/XML le cui API consentono di estrarre dati e manipolare in maniera estremamente semplice documenti sfruttando le potenzialità di DOM, CSS e metodi di accesso simili a quelli offerti da JQuery. Jsoup è un progetto open source sviluppato da Jonathan Hedley e distribuito sotto liberale licenza MIT. La libreria attualmente è in grado di fornire tali servizi: • Caricare pagine HTML da un URL, un file o una stringa; • Trovare ed estrarre i dati utilizzando un attraversamento DOM o dei selettori CSS; • Manipolare elementi HTML come attributi e testo; • Ricevere l’output con una struttura ben ordinata; • Organizzare i dati in una white-list sicura, per prevenire attacchi XSS. Jsoup è stato progettato per analizzare tutte le varianti di HTML presenti nella rete, poiché l’analizzatore crea per ogni pagina un albero di analisi sensibile. 3.2.2 Caricare documenti Jsoup come già menzionato permette di effettuare facilmente il parsing di una pagina HTML fornita come stringa, da file o direttamente come URL. In Jsoup un documento XML è rappresentato dalla classe Document, i nodi del documento da istanze della classe Node e i tag da istanze della classe Element. Volendo effettuare il parsing a partire da una stringa, si utilizza il seguente metodo statico: String html = "<html><head><title>First parse</title></head>" + "<body><p>Parsed HTML into a doc.</p></body></html>"; Document doc = Jsoup.parse(html, "http://example.com/"); 33 3.2 Libreria Jsoup Implementazione e Funzionamento Il metodo parse(String html, String baseUri) crea un nuovo Document con il codice HTML di ingresso. L’argomento baseUri viene utilizzato per risolvere URL relativi in URL assoluti, e deve essere impostato con l’URL in cui il documento è stato prelevato. É possibile utilizzare il metodo di base parse(String html) quando si conosce il codice HTML. Una volta che si è ottenuto un Document, è possibile estrarre i dati utilizzando i metodi appropriati della classe Document e delle sue super classi Element e Node. Se invece si desidera ottenere il documento HTML direttamente dall’URL si utilizza il metodo connect della classe Jsoup: Document doc = Jsoup.connect("http://example.com/").get(); Il metodo connect(String url) crea una nuova connessione e get() recupera e analizza la pagina HTML. Se dovesse verificarsi un errore durante il recupero, viene lanciata un’eccezione della classe IOException, il quale può essere gestita. L’interfaccia di collegamento è stata progettata per poter concatenare e costruire specifiche richieste, come ad esempio: Documento doc = Jsoup.connect ("http://example.com") .data ("query", "Java") .userAgent ("Mozilla") .cookie ("auth", "token") .timeout (3000) .post (); Per lo sviluppo dell’applicazione è stato utilizzato principalmente questo metodo poiché per la piattaforma ESSE3 le richieste erano di tipo POST, a differenza delle richieste GET di CampusNet. L’ultimo modo possibile per ottenere il documento è la lettura del codice HTML contenuto in un file attraverso il metodo statico della classe Jsoup: File input = new File("/tmp/input.html"); Document doc = Jsoup.parse(input, "UTF-8", "http://example.com/"); Il metodo parse(file in, String charsetName, String baseUri) carica e analizza un file contenente codice HTML. Se si verifica un errore durante il caricamento del file, esso genera un IOException, che si dovrebbe gestire in modo appropriato. 34 3.2 Libreria Jsoup 3.2.3 Implementazione e Funzionamento Estrazione e manipolazione dati Prima di procedere a spiegare i metodi della classe Document è opportuno ripetere alcuni concetti fondamentali. L’oggetto Document contiene tutti gli elementi della pagina Web, disposti in un albero mantenendone la struttura gerarchica originaria. Il contenuto delle pagine Web consiste in un documento HTML contenente una struttura ad albero annidato di elementi, definiti da marcatori detti tag, un esempio di struttura HTML è rappresentata in figura 3.3. Figura 3.3: Esempio di struttura documento HTML Il documento HTML contiene un tag di apertura, uno o più attributi di tale elemento con i rispettivi valori (che possono definirne colore, stile, posizione, etc), il contenuto informativo (che può essere una stringa di testo o una struttura di altri elementi) e infine un tag di chiusura. Un documento comincia con la definizione del tipo di pagina, la quale segnala al browser le specifiche HTML utilizzate, che permettono l’identificazione delle regole di interpretazione per visualizzare correttamente la pagina. Segue poi la struttura degli elementi che compongono la pagina, compresa tra i tag <HTML> . . . </HTML>, suddivisa in due sezioni principali: • Header è l’intestazione contenente alcune informazioni di controllo solitamente non visualizzabili. • Body è il corpo del documento che contiene la parte informativa, cioè la vera e propria pagina che sarà visualizzata dal browser. 35 3.2 Libreria Jsoup Implementazione e Funzionamento Una volta caricato il Document è possibile stanziare l’oggetto di tipo Element, il fulcro centrale della libreria, poiché grazie ad esso è possibile rappresentare un elemento (tag) ben specifico della pagina HTML con relativa sottostruttura. Quindi a partire da esso è possibile estrarre dati ed attraversare il grafo dei nodi. Document è sottoclasse di Element con alcuni metodi specifici per la radice di una pagina HTML, tra cui un metodo per ottenere il titolo e due metodi per ottenere l’Element di header o del body della pagina. Ricordando che un Document altro non è che l’Element radice di tutto l’albero. Il codice che viene riportato utilizza il metodo di attraversamento DOM: File input = new File ("/tmp/input.html"); Document doc = Jsoup.parse (input,"UTF-8","http://example.com/"); Element content = doc.getElementById("content"); Elements links = content.getElementsByTag("a"); for( Element link : links ){ String linkHref = link.attr("href"); String linkText = link.text(); } Il tipo Elements fornisce un range di metodi tipo DOM per cercare elementi e estrae e manipola i loro dati. I metodi get sono contestuali, chiamati su un nodo genitore Document cerca gli elementi corrispondenti in quel documento; mentre chiamate su un nodo figlio cerca gli elementi a partire da quel nodo. In questo modo è possibile cercare i dati che si vogliono utilizzare, vediamo ora i metodi applicabili su un oggetto Element per cercare i dati: • getElementById(String id) individua l’elemento con l’id indicato. L’id è un semplice attributo che deve però assumere per ogni elemento un valore univoco in tutto il documento HTML. • getElementsByTag(String tag) restituisce gli elementi di un certo tipo, ovvero quelli con il tag di apertura coincidente a quello da noi passato nella stringa tag. • getElementsByClass(String className) restituisce gli elementi con l’attributo class che assume il valore specificato. • getElementsByAttribute(String key) restituisce gli elementi che contengono un attributo così denominato. Esistono inoltre metodi associati che permettono di trovare elementi con attributi che iniziano, 36 3.2 Libreria Jsoup Implementazione e Funzionamento terminano o contengono la stringa desiderata; similmente esistono metodi che permettono di individuare elementi con attributi che assumono un valore desiderato (o soddisfano una certa espressione). I metodi forniti dalla libreria per attraversare la struttura, sono: • siblingElements() restituisce tutti i nodi dell’elemento allo stesso livello dell’albero; • firstElementSibling() restituisce il primo figlio del nodo; • lastElementSibling() restituisce l’ultimo figlio del nodo; • nextElementSibling() restituisce il prossimo figlio; • previousElementSibling() restituisce il figlio precedente; • parent() restituisce il nodo genitore; • parents() restituisce il nodo genitore e tutti gli ascendenti fino alla radice del documento compresi; • children() restituisce tutti i nodi figli; • child(int index) restituisce il nodo figlio con l’indice indicato dal parametro index. Un metodo alternativo più potente per trovare elementi consiste nell’uso dei selettori. I selettori permettono di selezionare e manipolare gli elementi HTML. Gli elementi possono essere identificati attraverso l’id, la classe, gli attributi, i valori degli attributi e altro ancora. In Jsoup la sintassi dei selettori è quella utilizzata da CSS e jQuery. La porzione di codice propone la ricerca con i selettori: File input = new File("/tmp/input.html"); Document doc = Jsoup.parse(input, "UTF-8", "http://example.com/"); Elements links = doc.select("a[href]"); Element masthead = doc.select("div.masthead").first(); Elements resultLinks = doc.select("h3.r > a"); I selettori possono essere chiamati su oggetti di tipo: Document, Element o Elements. Pertanto sono contestuali, quindi è possibile filtrare scegliendo un elemento specifico oppure una catena di selettori; la selezione restituisce 37 3.2 Libreria Jsoup Implementazione e Funzionamento un elenco contenuto nell’oggetto chiamante Elements, il quale fornisce una serie di metodi per estrarre e manipolare i risultati. I selettori principali sono: • tagname trova gli elementi per tag; • #id trova gli elementi per id; • .class trova gli elementi per classe; • [attr] elementi con nome dell’attributo coincidente; • [∧ attr] elementi con nome dell’attributo con tale prefisso; • [attr=value] elementi con attributo che assume il valore dato; • [attr∧ = value], [attr$ = value], [attr*= value] elementi con valore dell’attributo che inizia per, finisce o contiene la stringa data; I selettori possono essere combinati tra di loro, ad esempio: • el# id elementi con ID, esempio div# logo; • el.class elementi con classe class, esempio div.masthead; • el[attr] elementi con attributo attr, esempio a[href]; • ancestor child trova gli elementi child discendenti dall’elemento ancestor; • parent > child elementi child con genitore diretto parent; • siblingA + siblingB trova gli elementi siblingB con fratello immediatamente precedente siblingA; • siblingA ∼ siblingX cerca gli elementi siblingX precedente a siblingA, esempio h1 ∼ p; • el, el, el gruppo multiplo di selettori, cerca un unico elemento equivalente con i risultati di tutti i selettori, esempio div.logo. Tutti i selettori possono essere combinati tra loro, da qui la loro potenza rispetto ai singoli metodi visti precedentemente, vediamo ora alcuni esempi su codice HTML posto nel capitolo precedente. Per ottenere gli avvisi dalla pagina http://informatica.unipr.it/cgi-bin/campusnet/avvisi.pl, si è usato la combinazione di più selettori, ovvero: td.AVVISI-FORMAT-3 a 38 3.2 Libreria Jsoup Implementazione e Funzionamento poiché le informazioni che si vogliono ottenere sono poste tra i tag <A> . . . </A> nelle colonne della tabella (<TD> . . . </TD>) di classe=.AVVISIFORMAT-3. Esistono infine alcuni pseudo selettori che permettono di trovare elementi che contengono o non contengono elementi che soddisfano un certo selettore, o che corrispondono ad una espressione regolare: • :lt(n) cerca gli elementi figli il cui indice è inferiore rispetto a n (cioè la sua posizione nell’albero DOM rispetto al suo genitore); • :gt(n) cerca gli elementi figli il cui indice è maggiore rispetto a n; • :eq(n) cerca gli elementi figli il cui indice è uguale a n; • :has(seletor) cerca gli elementi che contengono elementi corrispondenti del selettore, esempio div:has(p); • :not(selector) cerca gli elementi che non coincidono con il selettore; • :contains(text) cerca gli elementi che contengono il testo dato; • :containsOwn(text) cerca gli elementi che contengono direttamente il testo dato; • :matches(regex) cerca gli elementi il cui testo corrisponde all’espressione regolare specificata; • :matchesOwn(regex) cerca gli elementi il cui testo proprio corrisponde all’espressione regolare specificata. I selettori si applicano utilizzando il metodo select(String cssQuery) della classe Element. Il metodo, come tutti gli altri metodi visti inizialmente, restituisce la lista di elementi come un oggetto di tipo Elements, implementazione dell’interfaccia List di Java. Per estrarre dati da un oggetto Element si utilizzano i seguenti metodi principali: • text() restituisce il testo puro contenuto tra tag di apertura e tag di chiusura; • attr(String name) restituisce il valore dell’attributo name; • html() restituisce il codice HTML racchiuso tra tag di apertura e chiusura; • outerHtml() restituisce il codice HTML esterno di definizione dell’elemento; 39 3.2 Libreria Jsoup Implementazione e Funzionamento Esistono infine metodi che consentono di aggiungere, modificare ed eliminare attributi dell’elemento e metodi che permettono di modificare l’albero stesso, aggiungere o rimuovendo elementi secondo la parentela desiderata. Questo consente, se desiderato, di usare Jsoup per modificare o persino creare da zero un documento HTML in modo procedurale con una chiara gerarchia. É possibile testare direttamente la libreria, semplicemente collegandosi al sito http://try.jsoup.org/ e incollare il codice HTML della pagina che si vuole effettuare il parse, oppure inserendo il link, a questo punto si possono applicare le diverse combinazioni di più selettori per ottenere le informazioni ricercate. 40 3.3 Architettura dell’applicazione 3.3 Implementazione e Funzionamento Architettura dell’applicazione Come già accennato, l’obiettivo è stato quello di progettare e realizzare un Applicazione per gli studenti del corso di Informatica capace di offrire informazioni importanti in tempo reale: avvisi, news, docenti, corsi, appelli e la propria carriera. Prima di passare alla parte implementativa sarebbe meglio chiarire l’architettura che si è scelto di utilizzare per poter realizzare tale progetto. Il pattern architetturale usato è il Model-View-Controller (MVC) uno dei più diffusi nella programmazione object oriented e nello sviluppo di interfacce grafiche in quanto rappresenta uno dei concetti fondamentali della programmazione ad oggetti e permette di strutturare l’applicazione in maniera molto efficiente. Aumenta la coesione del nostro sistema software, in quanto ogni singolo oggetto può ricoprire solo uno dei seguenti ruoli: modello, vista o controllore. Infatti ogni classe del progetto viene mirata a compiti ben specifici, inoltre questi ruoli rappresentano una sorta di classificazione dell’oggetto che stiamo utilizzando che risultano dunque essere elementi logicamente separati ai quali però è consentita, ovviamente, una stretta comunicazione. Il grafico in figura 3.4 illustra lo schema del design pattern utilizzato. Figura 3.4: Schema design pattern MVC Il pattern non solo stabilisce che ruolo deve avere un determinato oggetto all’interno dell’applicazione, ma anche il modo in cui gli oggetti comunicano tra di loro. Analizzando la struttura in figura 3.4 andiamo ad approfondire i tipi di oggetti che il pattern definisce: • Model: contiene i dati specifici dell’applicazione e si occupa di definire tutte le varie procedure che effettuano la manipolazione dei dati stessi, in lettura e scrittura. Il modello non può avere connessione diretta con un oggetto di tipo view, in quanto ha il compito di gestire i dati che non devono essere legati ad un particolare tipo di visualizzazione. 41 3.3 Architettura dell’applicazione Implementazione e Funzionamento • View: il ruolo della vista è quello di presentare all’utente i dati contenuti all’interno di un modello. Concettualmente il modello è un oggetto non concreto, mentre la vista è un oggetto concreto e con il quale l’utente può interagire. La vista è dunque una realizzazione di un oggetto non concreto e mette a disposizione un’interfaccia per la modifica dei dati contenuti nel modello. L’oggetto di tipo vista non deve avere un riferimento esplicito ad un oggetto di tipo modello e quindi a questo punto viene usato l’oggetto controllore. • Controller: svolge la funzione di intermediario tra oggetti di tipo vista ed oggetti di tipo modello. Un singolo controllore può avere un numero di relazioni arbitrarie tra oggetti di tipo modello e vista, che possono essere relazioni uno ad uno o molti a molti. Il controllore si occupa di inizializzare la vista con i dati contenenti nel modello e informare alla vista le modifiche dei dati subite dall’utente. 3.3.1 View L’interfaccia utente è stata progettata seguendo un semplice layout che rende intuitivo l’utilizzo, il menu principale permette la navigazione all’interno dell’applicazione. Utilizzando il GridLayout come impaginazione della vista, è stato possibile disporre bottoni e i relativi testi al centro della pagina, in una griglia formata da quattro righe e tre colonne. In figura 3.5 viene mostrata l’activity principale che si accede all’apertura dell’applicazione; composta da una griglia di sei bottoni allineati, uno per ogni funzionalità implementata, che sono: news, avvisi, docenti, corsi, appelli e carriera. L’utente toccando l’icona relativa alla sezione nella quale desidera accedere, entrerà in una vista secondaria contenente le informazioni desiderate. Figura 3.5: Schermata principale 42 3.3 Architettura dell’applicazione Implementazione e Funzionamento L’implementazione del layout di questa activity è avvenuta tramite codice XML, specificando gli attributi per ottenere tale struttura. <GridLayout xmlns:android="http://schemas.android.com/apk/res/android"> <ImageButton android:id="@+id/btnNews" android:layout_column="0" android:layout_row="0" android:background="@drawable/news" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:layout_column="0" android:layout_row="1" android:text="News" android:textAlignment="center" android:layout_height="wrap_content" android:layout_width="wrap_content" android:layout_gravity="center_horizontal" android:textStyle="bold" /> ... </GridLayout> Dalla porzione di codice appena mostrata si può osservare la struttura e la disposizione di ogni oggetto nel punto della griglia, ovvero grazie agli attributi android:layout_column e android:layout_row si specifica la posizione in cui si vuole mettere l’oggetto, possiamo notare che il bottone btnNews è nella posizione layout_column=0 layout_row=0 ovvero la prima cella della tabella, mentre il testo News è posizionato in layout_column=0 layout_row=1. Possiamo immaginare quindi la disposizione dei restanti componenti seguendo tale struttura. Per gestire le azioni che l’utente può svolgere dalla schermata è stata scritta la classe HomeActivity la quale estende la classe Activity, per ogni bottone viene descritta la procedura che l’applicazione deve svolgere. La porzione di codice mostra l’implementazione e le funzioni chiamate per realizzare il bottone News. 43 3.3 Architettura dell’applicazione Implementazione e Funzionamento public class HomeActivity extends Activity { private ImageButton btnNews; ... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_homepage); btnNews = (ImageButton) findViewById(R.id.btnNews); .... btnNews.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent i; i = new Intent(getApplicationContext(), FragmentManagerActivity.class); i.putExtra("fragment", 0); startActivity(i); } }); Il metodo setContentView(R.layout.activity_homepage), non è altro un riferimento alla risorsa che si vuole prelevare, ossia il layout che si è descritto precedentemente. Una volta caricata la risorsa è stato possibile stanziare l’oggetto btnNews di tipo ImageButton e inizializzarlo con il metodo findViewById(R.id.btnNews) il quale cerca l’elemento all’interno del layout con attributo id specificato tra parentesi. Volendo gestire il click sul bottone, si è usato il metodo OnClickListener() e si è ridefinito l’istanza del metodo OnClick(). In questo metodo è stato inserito il codice relativo al comportamento voluto quando il listener cattura l’evento a cui è associato. Data la presenza di due activity all’interno dell’applicazione è stato necessario fornire una funzionalità di navigazione tra di esse e per fare questo si è fatto uso degli Intent. Viene dichiarato un oggetto esplicito di tipo Intent e viene istanziato fornendo come parametri il contesto dell’activity e l’activity versa la quale è rivolto l’intent. Inoltre viene spedito un messaggio generalmente chiamato Extras e può essere di varie tipologie, sia appartenenti a classi più comuni che ad altre purché serializzabili. Il metodo i.putExtra(fragment, 0) manda l’extra etichettato con una chiave fragment e il valore 0 che verrà poi 44 3.3 Architettura dell’applicazione Implementazione e Funzionamento gestito nell’activity secondaria. Infine il metodo startActivity(i) dimostra l’azione che si vuole attivare con questo Intent. Verrà spiegato in seguito il motivo del messaggio che si è voluto mandare verso l’activity secondaria FragmentManagerActivity. News/Avvisi Toccando l’icona relativi agli avvisi, viene aperta una seconda activity istanziando un fragment contenente una lista ordinata degli avvisi di CampusNet, caratterizzati da un titolo in grassetto di colore blu e dall’autore presentato in corsivo di colore grigio, come noto in figura 3.6. Si è scelto di utilizzare i fragment per poter creare una sola activity secondaria che svolge il ruolo di contenitore, ecco il motivo dell’invio del messaggio extra contenente la chiave fragment e un valore intero, mediante il quale viene istanziato il fragment con indice uguale al valore ricevuto. Identica è la scelta utilizzata per mostrare le news. Il componente di Android utilizzato per creare la lista è ListView, un gruppo che mostra un elenco di elementi scorrevoli. Le voci di elenco vengono inserite automaticamente utilizzando un adattatore che Figura 3.6: Schermata avvisi inietta i contenuti da una fonte, nel nostro caso dal database e converte ogni voce in una vista che verrà poi inserita nella lista. Il layout per rappresentare la ListView è dato dal seguente codice XML: <ListView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/listaAvvisi" android:layout_alignParentRight="true" android:layout_alignParentEnd="true" android:footerDividersEnabled="true" /> 45 3.3 Architettura dell’applicazione Implementazione e Funzionamento I dati da mostrare e il layout di una singola cella vengono definiti da un ListAdapter, infatti una ListView ha sempre associato un ListAdapter; è una interfaccia Java implementata a secondo del contesto, nel nostro caso si è scelta la classe ArrayAdapter poichè gestisce una lista di oggetti di tipo Avviso. I valori sono stati inseriti con il metodo setText() nelle TextView definite all’interno del layout layout_row_avvisi. Possiamo immaginare la struttura del layout contenente due TextView, una per il titolo e l’altra per l’autore dell’avviso. La porzione di codice implementa l’adattatore, il quale nel metodo getView gestisce la lista di avvisi e la rende adattabile a una qualsiasi ListView. Per ogni oggetto avviso vengono chiamati i metodi getTitolo() e getData(), poiché sono le informazioni che si vogliono visualizzare all’interno della lista. public class ArrayAdapterAvvisi extends ArrayAdapter<Avviso> { private final Context context; private final Avviso[] values; public ArrayAdapterAvvisi(Context context, Avviso[] values) { super(context, R.layout.layout_row_avvisi, values); this.context = context; this.values = values; } @Override public View getView(int position, View convertView, ViewGroup parent) { LayoutInflater inflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); View rowView = inflater.inflate(R.layout.layout_row_avvisi, parent, false); TextView titolo = (TextView) rowView.findViewById(R.id.titolo); TextView data = (TextView) rowView.findViewById(R.id.data); titolo.setText(values[position].getTitolo()); data.setText(values[position].getData()); return rowView; } } 46 3.3 Architettura dell’applicazione Implementazione e Funzionamento Una volta creato l’adattatore basta semplicemente creare e poi istanziare ArrayAdapterAvvisi(getActivity(), arrayAvvisi) passandogli come parametro l’activity e l’array di oggetti da visualizzare nella lista. Possiamo notare dal frammento di codice che una volta presi gli avvisi dalla base di dati vengono poi inseriti all’interno di un array di tipo avvisi e adattati alla lista. Se il database non contiene avvisi verrà mostrato un testo all’interno della schermata che indica la non presenza di avvisi. É stato utilizzato tale metodo per la visualizzazione delle altre sezioni disponibili nell’applicazione, effettuando opportune modifiche. public class AvvisiFragment extends Fragment { private ListView listView; ... @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { ... databaseManager = new DatabaseManager(getActivity()); databaseManager.open(); avvisi = databaseManager.fetchAllAvvisi(); databaseManager.close(); if(avvisi.size() > 0) { Avviso[] arrayAvvisi = new Avviso[avvisi.size()]; int i = 0; for (Avviso a : avvisi) { arrayAvvisi[i] = a; i++; } ArrayAdapterAvvisi adapter = new ArrayAdapterAvvisi(getActivity(), arrayAvvisi); listView.setAdapter(adapter); }else { textAssenza.setText("Non ci sono avvisi."); } ... } 47 3.3 Architettura dell’applicazione Implementazione e Funzionamento Docenti Toccando l’icona relativi ai docenti, viene aperta la seconda activity istanziando un fragment contenente una lista ordinata dei docenti presenti sulla piattaforma CampusNet, come noto in figura 3.7. La tecnica è praticamente la stessa usata per tutte le schermate avente al loro interno una lista; le voci di elenco vengono inserite automaticamente utilizzando in questo caso un adattatore predefinito layout.simple_list_item_1, che inietta i contenuti da una fonte, nel nostro caso dal database e converte ogni voce in una vista che verrà poi inserita nella lista. In questo caso l’informazione visualizzata per ogni riga è il nome completo del docente. Volendo ottenere maggiori dettagli, per esempio: indirizzo, contatto, ruolo, orario di ricevimento studenti e interessi, basterà cliccare sulla riga del docente di interesse. Il codice Figura 3.7: Schermata docenti propone la richiesta al database per ottenere l’elenco dei docenti e l’inserimento all’interno di un array di stringhe per adattarli alla lista. databaseManager.open(); docenti = databaseManager.fetchAllDocenti(); databaseManager.close(); String[] nome = new String[docenti.size()]; int i = 0; for(Docente a: docenti){ nome[i] = a.getNome(); i++; } ArrayAdapter<String> adapter = new ArrayAdapter<String>(rootView.getContext(), android.R.layout.simple_list_item_1 ,nome); listaDocenti.setAdapter(adapter); 48 3.3 Architettura dell’applicazione Implementazione e Funzionamento Corsi Toccando l’icona relativi ai corsi, viene aperta la seconda activity istanziando un fragment contenente una lista ordinata dei corsi presenti sulla piattaforma CampusNet, come è possibile notare in figura 3.8. La struttura della lista è praticamente identica a quella degli avvisi. Poiché le informazioni da visualizzare per ogni riga sono due: il nome del corso e il docente che lo tiene. Infatti l’adattatore utilizzato in questo caso è simile a quello precedentemente proposto; deve gestire anche in questo caso due TextView, una per il nome del corso e l’altra per il docente, infatti le informazioni visualizzate per ogni riga sono due come si può notare dalla figura 3.8. Volendo ottenere maggiori dettagli come: tipologia del corso, crediti, obiettivi formativi, programma o testi consigliati basterà cliccare sulla riga del corso di interesse. Il codice ripropoFigura 3.8: Schermata corsi ne la richiesta al database per ottenere l’elenco dei corsi e l’inserimento all’interno di un array di tipo Corsi per adattarli alla lista. databaseManager = new DatabaseManager(getActivity()); databaseManager.open(); corsi = databaseManager.fetchAllCorsi(); databaseManager.close(); Corso[] arrayCorso = new Corso[corsi.size()]; int i = 0; for(Corso a: corsi){ arrayCorso[i] = a; i++; } ArrayAdapterCorsi adapter = new ArrayAdapterCorsi(getActivity(), arrayCorso); listCorsi.setAdapter(adapter); 49 3.3 Architettura dell’applicazione Implementazione e Funzionamento Appelli Figura 3.9: Schermata appelli Toccando l’icona relativi agli appelli, viene aperta la seconda activity istanziando un fragment contenente uno spinner e una lista inizialmente vuota. Lo spinner fornisce un modo rapido per selezionare un valore da un elenco. Nello stato di default, viene mostrato seleziona il corso di laurea. Toccando su di esso si visualizza un menu a discesa con tutti gli altri corsi di studio disponibili: [1101] informatica, [3027] informatica, [0314] informatica, [0275] matematica e informatica. L’utente può selezionare il proprio corso di studio e visualizzare dinamicamente gli appelli disponibili ordinati in base alla data. Le informazioni che vengono visualizzate per ogni riga sono: il corso (colore blu), il periodo di iscrizione (colore grigio) e la data dell’appello (colore rosso). Il layout di tale schermata è stato strutturato attraverso tale porzione di codice XML. <Spinner android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/spinnerCorsi" android:layout_gravity="center_horizontal" android:clickable="true" android:entries="@array/corso_di_studio"/> <ListView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/listAppelli" android:layout_gravity="center_horizontal" /> z 50 3.3 Architettura dell’applicazione Implementazione e Funzionamento Le informazioni sono state prese dalla piattaforma ESSE3 all’url https: //unipr.esse3.cineca.it/ListaAppelliOfferta.do con richieste di tipo POST, restringendo il campo di ricerca solo per i corsi di studio di informatica. In questo caso i dati non risiedono nella base di dati poiché sono in continuo aggiornamento. Quindi la scelta è stata di far gestire al controllore i vari scaricamenti delle informazioni ogni volta che si effettua la scelta del corso di studio. L’adattatore in questo caso gestisce l’oggetto di tipo Appello con il layout di riga stabilito, infatti viene creato un oggetto di tipo View e instanziato con il layout layout_row_appelli. Dalla porzione codice è possibile osservare quanto detto. private final Context context; private final Appello[] values; public ArrayAdapterAppelli(Context context, Appello[] values) { super(context, R.layout.layout_row_appelli, values); this.context = context; this.values = values; } @Override public View getView(int position, View convertView, ViewGroup parent) { LayoutInflater inflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); View rowView = inflater.inflate(R.layout.layout_row_appelli, parent, false); TextView titolo = (TextView) rowView.findViewById(R.id.titolo); TextView periodo = (TextView) rowView.findViewById(R.id.periodo); TextView data = (TextView) rowView.findViewById(R.id.dataEora); titolo.setText(values[position].getTitolo()); periodo.setText(values[position].getPeriodoIscrizione()); data.setText(values[position].getDataOraEsame()); return rowView; } 51 3.3 Architettura dell’applicazione Implementazione e Funzionamento Carriera Toccando l’ultima icona relativa alla carriera, viene aperta la seconda activity istanziando un fragment contenente un WebViewClient e una ListView inizialmente non visibile data la presenza della WebView. Una WebView è un tipo di View che permette di visualizzare pagine Web. La sua utilità principale è quella di permettere di integrare con una Web application o più in generale un sito Web nella propria applicazione. Il motore del WebView risiede nella libreria WebKit già inclusa all’interno di Android per questo possiamo parlare di questo componente come di un browser vero e proprio in grado di eseguire Javascript e mostrare layout nella maniera più completa possibile. La figura 3.10 mostra il primo accesso a questa sezione, viene visualizzata la pagina di autenticazione poiché i dati che si vogliono recuFigura 3.10: Schermata login perare sono accessibili solo dopo essersi autenticati alla piattaforma ESSE3. Per ottenere questo risultato si è creato un layout come il seguente. <WebView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/webView" android:layout_alignParentEnd="true" android:layout_alignParentStart="true" /> <ListView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/listView" android:layout_alignParentStart="true" android:layout_below="@+id/space" /> 52 3.3 Architettura dell’applicazione Implementazione e Funzionamento Una volta che l’utente ha immesso la propria mail e password dell’ateneo, la WebViewClient viene resa invisibile e si visualizza la lista degli esami verbalizzati con il rispettivo voto e la media ponderata dei voti nella barra delle azioni, come in figura 3.11. Anche in questo caso i dati vengono presi direttamente dalla piattaforma ESSE3. Per poter ricavare l’HTML di tale pagina si è fatto uso di una strategia che tante applicazioni al giorno d’oggi adottano, ovvero una volta istanziato l’oggetto di tipo WebView viene fatto Overraide del metodo onPageFinished() ciò vuol dire riuscire a gestire il fine del caricamento di ogni pagina Web. Infatti nella porzioni di codice si può notare lo statement if con la clausola url.equals() la quale una volta finita di caricare la pagina del libretto universitario su ESSE3 la WebView viene settata Figura 3.11: Schermata carriera in modalità invisibile. La strategia utilizzata per poter ottenere i dati verrà poi descritta in maniera più accurata nella prossima sezione di questo capitolo. webView.setWebViewClient(new WebViewClient(){ @Override public void onPageFinished(WebView view, String url) { if(url.equals("https://unipr.esse3.cineca.it/auth/" +"studente/Libretto/LibrettoHome.do")){ view.setVisibility(View.GONE); ... 53 3.3 Architettura dell’applicazione 3.3.2 Implementazione e Funzionamento Model Database I dati vengono organizzati in una base dati, questa scelta è stata pensata per poter permettere agli utenti di accedere alle informazioni anche in assenza di segnale internet (3G) ovvero la cosiddetta modalità offline. SQLite è un leggerissimo database engine transazionale che occupa poco spazio in memoria e sul disco (da circa 4KiB a circa 350KiB, a seconda del target della piattaforma), pertanto è la tecnologia perfetta per creare e gestire database in un ambiente come quello degli applicativi mobile, dove le risorse sono molto limitate e dunque è molto importante ottimizzarne l’utilizzo. A differenza della maggior parte degli altri database SQL, SQLite non ha un processo server separato ma legge e scrive direttamente su file ordinari sul disco: possiede praticamente tutti gli strumenti principali che caratterizzato i più importanti database SQL (tabelle, viste, indici, trigger) ed il codice è distribuito gratuitamente sia per scopi commerciali che privati. SQLite è più diffuso di quanto ci si aspetterebbe, infatti viene utilizzato in moltissimi applicativi e device che utilizziamo quotidianamente, come: iPhone, Mozilla Firefox, negli smartphone Symbian, in Skype, in diversi applicativi PHP o Adobe AIR, e in molti altri progetti. Un database SQLite è, nella pratica, un file: possiamo spostarlo, copiarlo in un altro sistema (ad esempio dallo smartphone al nostro pc) e continuerà a funzionare tutto regolarmente. Android fa uso di SQLite, considerato appunto il motore di database più diffuso al mondo. Rispetta tutti i requisiti di efficienza e disponibilità di cui si è detto. Si tratta, in realtà, di una libreria software che permette di gestire in un unico file un database relazionale. Oltretutto è un progetto in continua espansione che mette a disposizione molti aspetti dei moderni DBMS: View, Trigger, transazioni, indici oltre al comunissimo e comodissimo interfacciamento con linguaggio SQL. Android memorizza i file seguendo uno schema preciso; il file SQLite del database dell’applicazione viene memorizzato in una directory il cui percorso è: /data/data/it.unipr.informatica.bartolomeo.appcampusnet/databases dove it.unipr.informatica.bartolomeo.appcampusnet è il nome del package dell’applicativo. Per accedere al file del database dalla nostra app abbiamo ovviamente a disposizione gli statements SQL. Grazie alle classi che vedremo e che permettono di implementare helper e adapter. Il database implementato per questa applicazione è molto semplice e intuitivo poiché tutte le tabelle contenute nella struttura sono indipendenti, ciò vuol dire non avere relazioni logiche tra le entità. I dati che si sono scelti di tenere in modalità offline sono: le news, gli avvisi, i docenti e i corsi. Infatti il codice propone l’im- 54 3.3 Architettura dell’applicazione Implementazione e Funzionamento plementazione della classe helper che permette di creare il database con le rispettive tabelle. public class DatabaseHelper extends SQLiteOpenHelper { private static final String DATABASE_NAME = "database.db"; private static final String DATABASE_CREATE_AVVISI = "CREATE TABLE AVVISI(" + "TITOLO TEXT PRIMARY KEY," + "LINK TEXT NOT NULL," + "DATA TEXT NOT NULL)"; private static final String DATABASE_CREATE_NEWS = "CREATE TABLE NEWS(" + "TITOLO TEXT PRIMARY KEY," + "LINK TEXT NOT NULL," + "DATA TEXT NOT NULL)"; private static final String DATABASE_CREATE_DOCENTI = "CREATE TABLE DOCENTI(" + "NOME TEXT PRIMARY KEY," + "LINK TEXT NOT NULL)"; private static final String DATABASE_CREATE_CORSI = "CREATE TABLE CORSI(" + "NOME TEXT PRIMARY KEY," + "LINK TEXT NOT NULL," + "DOCENTE TEXT NOT NULL)"; public DatabaseHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase database) { database.execSQL(DATABASE_CREATE_AVVISI); database.execSQL(DATABASE_CREATE_NEWS); database.execSQL(DATABASE_CREATE_DOCENTI); database.execSQL(DATABASE_CREATE_CORSI); } } 55 3.3 Architettura dell’applicazione Implementazione e Funzionamento Dal codice proposto è possibile notare l’override del metodo onCreate, questo viene invocato nel momento in cui non si trova nello spazio dell’applicazione un database con nome indicato nel costruttore. Il metodo verrà invocato una sola volta, ovvero quando il database non esiste ancora. Il parametro passato in input è un riferimento all’oggetto che astrae il database. La classe SQLiteDatabase è importantissima in quanto per suo tramite invieremo i comandi di gestione dei dati. Il metodo onCreate contiene la query SQL che serve a creare il contenuto del database. Una volta creato il database si è scelto di affidare la gestione del database alla classe che prende il nome di DatabaseManager, l’obiettivo di tale classe è avere metodi che eseguono query SQL sulla base di dati per estrarre e manipolare dati da questa. La classe DatabaseManager fornisce per l’appunto l’interfaccia diretta per manipolare il database. Un Manager è, nella pratica, un livello di astrazione: fornisce tutta una serie di metodi che, una volta testati opportunamente, permettono la creazione, la cancellazione, la modifica o la manipolazione di record nel database. Inizialmente vengono definite alcune proprietà e alcune costanti che verranno utilizzate massicciamente all’interno della classe: la prima costante definisce il nome della tabella mentre le altre definiscono il nome di ogni colonna della stessa. Da questo momento in poi per l’implementazione del manager verranno utilizzate queste costanti nelle query SQL, in modo da poterne modificare il nome in caso di necessità senza dover riscrivere tutte le query. Il codice riportato mostra soltanto i metodi implementati per la tabella avvisi poiché sono logicamente equivalenti alle altre. public class DatabaseManager { private static final String DATABASE_TABLE_AVVISI = "AVVISI"; ... public static final String KEY_TITOLO = "TITOLO"; public static final String KEY_LINK = "LINK"; public static final String KEY_DATA = "DATA"; ... public DatabaseManager open() throws SQLException { dbHelper = new DatabaseHelper(context); database = dbHelper.getWritableDatabase(); return this; } public void close() { dbHelper.close(); } 56 3.3 Architettura dell’applicazione Implementazione e Funzionamento private ContentValues createContentValues(String titolo, String link, String data) { ContentValues values = new ContentValues(); values.put( KEY_TITOLO, titolo ); values.put( KEY_LINK, link ); values.put( KEY_DATA, data); return values; } public long createAvviso(String titolo, String link, String data){ ContentValues initialValues = createContentValues(titolo,link,data); return database.insertOrThrow(DATABASE_TABLE_AVVISI, null, initialValues); } public int deleteAvvisi() { return database.delete(DATABASE_TABLE_AVVISI, null, null); } public List<Avviso> fetchAllAvvisi() { Cursor cursor; List<Avviso> avvisoList = new LinkedList<Avviso>(); cursor = database.query(DATABASE_TABLE_AVVISI, new String[] {KEY_TITOLO, KEY_LINK, KEY_DATA}, null, null, null, null, null); while(cursor.moveToNext()){ String titolo = cursor.getString(cursor .getColumnIndex(DatabaseManager.KEY_TITOLO)); String link = cursor.getString(cursor .getColumnIndex(DatabaseManager.KEY_LINK)); String data = cursor.getString(cursor .getColumnIndex(DatabaseManager.KEY_DATA)); avvisoList.add(new Avviso(titolo, link, data)); } cursor.close(); return avvisoList; } I metodi open() e close(), sono metodi che verranno usati ogni volta che si dovrà comunicare con il database: sarà intatti sufficiente chiamare questi 57 3.3 Architettura dell’applicazione Implementazione e Funzionamento metodi per poter lavorare con il database. All’interno viene stanziato un oggetto di tipo DatabaseHelper che, come abbiamo visto, fornisce l’interfaccia di creazione/aggiornamento/gestione del database. Dopodiché viene invocato il metodo getWritetableDatabase() definito in SQLiteOpenHelper, il quale restituisce un oggetto database in modalità lettura/scrittura attivo fino a quando non viene richiamato il metodo close(). La prima volta che viene chiamato getWritableDatabase() il database viene aperto e vengono automaticamente richiamato il metodo onCreate() e se necessario anche il metodo onOpen(). Il metodo close() invece non fa altro che richiamare il metodo close() della classe SQLiteOpenHelper, il quale chiude ogni oggetto database aperto. Un metodo molto importante è quello che implementa l’operazione di creazione di un nuovo avviso. createAvviso() richiede 3 parametri in ingresso: titolo, link e data, i parametri utili per identificare un nuovo avviso. Dopo aver richiamato createContentValues(), il metodo utilizza l’istanza SQLiteDatabse database correttamente impostata nel metodo open() per richiamare la funzione insertOrThrow(): questa permette di inserire un record nel database e prende come parametri in input il nome della tabella in cui inserire la riga in questo caso DATABASE_TABLE_AVVISI, un valore che indica come comportarsi nel caso in cui i valori iniziali siano vuoti ed infine i valori da inserire. Il secondo parametro stabilisce il comportamento della insert nel caso in cui initialValues sia vuoto: se non impostato a null, il parametro indica in quali colonne vogliamo che sia inserito un null lì dove initialValues è vuoto. Il metodo deleteAvvisi() è molto più semplice ed intuitivo, poiché va a cancellare l’intera tabella contenente gli avvisi. É stato utile in quanto ad ogni avvio dell’applicazione viene richiamato tale metodo per semplificare la sincronizzazione, ovvero cancellare e aggiornare con i nuovi avvisi disponibili su CampusNet. L’ultimo metodo è fetchAllAvvisi() ovvero è un metodo che permette di recuperare tutti gli avvisi presenti nel nostro database. Si utilizza un istanza della classe SQLiteDatabase per richiamare la funzione specifica messa a disposizione dalla piattaforma Android, in questo caso a noi interessa la funzione query(). Questa funzione, in base ai parametri passati, genera le query necessarie per interrogare il database e recuperare i dati che ci interessano. La funzione query() restituisce un oggetto di tipo Cursor: questo oggetto fornisce l’accesso in modalità di lettura-scrittura al result set restituito dalla query. Il metodo moveToNext() utilizzato nella clausola del while, muove il cursore alla riga successiva, dalla quale possiamo ricavare il valore che ci interessa attraverso il metodo getColumnIndex(), che restituisce l’indice della colonna richiesta, e il metodo getString(), che invece ritorna come 58 3.3 Architettura dell’applicazione Implementazione e Funzionamento stringa il valore della colonna richiesta. Ad ogni ciclo quindi vengono presi gli avvisi dalla base di dati e vengono aggiunti alla lista avvisoList di tipo List<Avviso>, infatti all’interno dell’applicativo le informazioni vengono condivise da tali liste una per ogni tipo di oggetto: News, Avviso, Docenti e Corsi. Alla fine dell’estrazione delle informazioni viene chiuso il cursore con il metodo close(), che rilascia tutte le risorse invalidandolo completamente. Modello dei dati La manipolazione dei dati è avvenuta grazie alla presenza di classi modello, la base della programmazione orientata agli oggetti. Il modello comprende attributi e metodi che verranno condivisi da tutti gli oggetti creati a partire dalla classe. Un oggetto infatti è l’istanza di una classe. Una classe è identificabile come un tipo di dato astratto che può rappresentare l’astrazione di un concetto. Fondamentalmente, vengono definiti al proprio interno lo stato, i cui dati sono memorizzati nelle cosiddette variabili membro o attributi, e il comportamento dell’entità di cui è rappresentazione, descritto da blocchi di codice riutilizzabili chiamati metodi. Quando il parser ricava le informazioni dalla rete deve istanziare dei nuovi oggetti di tipo: news/avviso, docenti, corsi, appello e esame. Queste classi contengono degli attributi, ovvero le proprietà che ogni oggetto deve avere. Ad esempio nel caso degli avvisi, come abbiamo appena visto, nel database vengono salvate tre informazioni per ogni entità: il titolo, il link e la data di emissione. Quindi ogni avviso predispone di attributi, infatti è stata costruita una classe avente delle proprietà che il singolo oggetto avviso deve contenere. Si sono implementate cinque classi diverse una per ogni sezione dell’applicativo, poiché le informazioni da ricavare sono totalmente differenti tra di loro, a parte per le news che hanno la stessa forma degli avvisi. La classe Avviso/News: private String titolo; private String link; private String data; La classe Docente: private String nome; private String link; 59 3.3 Architettura dell’applicazione Implementazione e Funzionamento La classe Corso: private String nome; private String link; private String docente; La classe Appello contiene tali attributi: private private private private private private private String String String String String String String titolo; periodoIscrizione; dataOraEsame; tipo; tipoProva; docente; numIscritti; La classe Esame per la manipolazione dei dati della sezione carriera ha queste proprietà: private private private private private private String String String String String String annoCorso; nome; crediti; aaFreq; voto; data; Tutte le classi appena descritte contengono i metodi getter e setter per ogni attributo, generalmente le classi definiscono metodi getter che forniscono accesso in lettura e metodi setter che forniscono accesso in scrittura a una data proprietà. Il discorso può sembrare assurdo ma un oggetto non è altro che un elemento dotato di attributi e metodi o in parole povere di variabili e funzioni, la cosa importante da dire è che tali attributi sono nascosti, o meglio incapsulati nei metodi, in modo tale da nascondere agli utenti le proprie caratteristiche le quali sono accessibili solo mediante le funzioni. Un metodo getter non accetta parametri e restituisce sempre un valore, mentre un metodo setter accetta sempre un parametro e non restituisce mai valori. 60 3.3 Architettura dell’applicazione Implementazione e Funzionamento Parse pagine CampusNet Per ricavare le informazioni dalle varie piattaforme si è fatto uso della libreria Jsoup, descritta precedentemente. Verranno mostrare le varie classi che permettono di effettuare il parse delle pagine Web, mostrando le varie configurazioni di selettori CSS. Per implementare ed eseguire il parse si è fatto uso della classe AsyncTask. La classe AsyncTask di Android consente di effettuare delle elaborazioni in background e quindi gestire i risultati dal tread principale. Solitamente viene utilizzata per eseguire operazioni di breve durata. Ogni elaborazione asincrona si compone di circa 4 passi che Android esegue consecutivamente e sono onPreExecute, doInBackground, onProgressUpdate and onPostExecute. Infatti le operazioni vengono svolte nel metodo doInBackground ovvero le azioni che il task deve svolgere in background. public class ParseAvvisiNews extends AsyncTask<String,Void,List<Avviso>>{ private List<Avviso> avvisi; @Override protected List<Avviso> doInBackground(String... strings) { avvisi = new LinkedList<>(); try { Document doc = Jsoup.connect(strings[0]).get(); Elements topicList = doc.select(strings[1]); Avviso avviso; ParseData p = new ParseData(); for(Element topic : topicList){ String titolo = topic.text(); String link = topic.attr("href"); String data = p.doInBackground(link).toString(); avviso = new Avviso(titolo, link, data); avvisi.add(avviso); } } catch (Throwable t) { t.printStackTrace(); } return avvisi; } } 61 3.3 Architettura dell’applicazione Implementazione e Funzionamento La porzione di codice proposta implementa la classe per effettuare il parse degli avvisi/news, passando come parametri l’url e il selettore. Il metodo connect(String url) crea una nuova connessione e get() recupera e analizza la pagina HTML. Una volta che si è ottenuto il Document, è possibile estrarre i dati utilizzando i metodi appropriati della classe Document e delle sue super classi Element e Node. A questo punto è possibile stanziare l’oggetto di tipo Element, il fulcro centrale della libreria, poiché grazie ad esso è possibile rappresentare un elemento (tag) ben specifico della pagina HTML con relativa sottostruttura. Quindi a partire da esso è possibile estrarre dati ed attraversare il grafo dei nodi. Infatti scorrendo la lista topicList per ogni Element si catturano i dati: titolo, link e data. Il tutto viene poi impacchettato in un oggetto di tipo Avviso e si aggiunge alla lista di avvisi. All’apertura dell’applicativo viene invocata una funzione che popola il database, infatti viene istanziato un oggetto di tipo ParseAvvisiNews e viene invocato il metodo che effettua appunto il parse della pagina http:// informatica.unipr.it/cgi-bin/campusnet/home.pl. try { avvisi = parseAvvisiNews.execute(new String[]{ "http://informatica.unipr.it/cgi-bin/campusnet/avvisi.pl", "td.AVVISI-FORMAT-3 a"}).get(); news = parseURLnews.execute(new String[]{ "http://informatica.unipr.it/cgi-bin/campusnet/avvisi.pl", "td.AVVISI-FORMAT-4 a"}).get(); }catch (Exception e) { ... } if(!avvisi.isEmpty()) { databaseManager.deleteAvvisi(); for (Avviso avviso : avvisi) { String titolo = avviso.getTitolo(); String link = avviso.getLink(); String data = avviso.getData(); databaseManager.createAvviso(titolo, link, data); } } 62 3.3 Architettura dell’applicazione Implementazione e Funzionamento Per ottenere gli avvisi dalla pagina di CampusNet, si è usato la combinazione di più selettori, come è possibile notare dalla porzione di codice, ovvero: td.AVVISI-FORMAT-3 a poiché le informazioni che si vogliono ottenere sono poste tra i tag <A> . . . </A> nelle colonne della tabella (<TD> . . . </TD>) di classe=.AVVISI-FORMAT-3. Parse pagine ESSE3 Le classi che effettuano parsing delle pagine contenente informazioni sui docenti e i corsi sono logicamente equivalenti poiché sono pagine della stessa piattaforma CampusNet, mentre è doveroso descrivere la tecnica utilizzata per ricavare i dati dal Learning Management System ESSE3, strutturata in maniera diversa rispetto questa. La piattaforma ESSE3 comunica mediante richieste POST, la libreria Jsoup permette questo metodo di connessione, infatti possiamo notare dalla porzione di codice che viene invocato un metodo durante l’inizializzazione della connect passando come parametro una costante Connection.Method.POST. @Override protected List<Appello> doInBackground(String... strings) { private List<Appello> appelloList; appelloList = new LinkedList<>(); try { Connection.Response res = Jsoup.connect(strings[0]) .data("TIPO_FORM","1","fac_id","10024", "cds_id",strings[1],"ad_id","", "docente_id","","data","", "btnSubmit","Avvia+Ricerca") .method(Connection.Method.POST) .execute(); Document doc = res.parse(); Elements topicList = doc.select(strings[2]); Appello appello = new Appello(); for(Element topic : topicList) { ... appelloList.add(appello); appello = new Appello(); } } return appelloList; } 63 3.3 Architettura dell’applicazione Implementazione e Funzionamento Con il metodo data() è possibile aggiungere parametri di richiesta di dati, tali parametri vengono inviati nel corpo della richiesta. Questo poiché alla pagina https://unipr.esse3.cineca.it/ListaAppelliOfferta.do prima di avviare la ricerca degli appelli, è doveroso impostare il dipartimento e il corso di studio; grazie al metodo data() è possibile inviare tali parametri utili alla ricerca che identificano gli appelli del corso di informatica. La tecnica che si è scelta di usare per ricavare il sorgente HTML per la sezione della carriera è molto interessante, in quanto dopo svariati tentativi di approccio con il protocollo che gestisce la parte di login CAS non è risultato semplice. Non è stato possibile creare una connessione neanche con Jsoup, in quanto la libreria non supporta tale protocollo usato dall’università di Parma. Questo perché la piattaforma ESSE3 usa un servizio per l’autenticazione Single Sign-On (SSO) di una comunità Web, in questo caso l’università di Parma. I componenti sono: il CAS server, che gestisce l’identità della comunità (Identity Provider) e i Service Providers, che forniscono le applicazioni che richiedono accesso autenticato. Utilizza un proprio protocollo basato su HTTP e sulla redirezione dell’url. Figura 3.12: Autenticazione CAS Quindi per ovviare questo problema di scambi e redirezione dei pacchetti, l’idea è stata quella di effettuare il login attraverso una WebView, cosicché la gestione dei pacchetti è lasciata direttamente al componente. Una volta 64 3.3 Architettura dell’applicazione Implementazione e Funzionamento effettuato il login, viene nascosta la WebView e viene chiamata una funzione JavaScript per la cattura e l’esportazione su file del sorgente HTML della pagina contenente la tabella dei voti, https://unipr.esse3.cineca. it/auth/studente/Libretto/LibrettoHome.do. Questo metodo è risultato più veloce ed efficiente per accedere al sorgente HTML. Viene mostrato la porzione di codice che identifica, una volta resa la WebView invisibile, la chiamata showHTML mediante interfaccia JavaScript. webView.setWebViewClient(new WebViewClient(){ @Override public void onPageFinished(WebView view, String url) { if(url.equals("https://unipr.esse3.cineca.it/auth/" +"studente/Libretto/LibrettoHome.do")){ view.setVisibility(View.GONE); view.loadUrl("javascript:window.HtmlViewer.showHTML"+ "(’<html>’ +document.getElementsByTagName(’html’)[0].innerHTML +’</html>’);"); ... } } } La classe con il metodo showHTML è definita come @JavascriptInterface, ovvero una procedura JavaScript, infatti viene invocata nella query javascript:window.HtmlViewer.showHTML, l’output della funzione restituisce una stringa contenente l’HTML completo della pagina. class MyJavaScriptInterface { private Context ctx; MyJavaScriptInterface(Context ctx) { this.ctx = rootView.getContext(); } @JavascriptInterface public void showHTML(String html) { write(html); } ... } 65 3.3 Architettura dell’applicazione Implementazione e Funzionamento Una volta ottenuto l’HTML viene passato alla funzione write() che presa una stringa, crea un file di contenuto html nella memoria del dispositivo. Dopodiché viene fatto partire il parse caricando tale file contente l’HTML. La porzione di codice mostra il caricamento del file è l’istanza dell’albero Elements con il selettore .detail_table td. File input = new File("/storage/emulated/0/html.txt"); Document doc = null; try { doc = Jsoup.parse(input, "UTF-8", ""); } catch (IOException e) { e.printStackTrace(); } Elements topicList = doc.select(".detail_table td"); A questo punto è bastato scorrere la lista di Element e settare le proprietà per ogni oggetto esame creato, ovvero: anno di corso, codice e nome dell’insegnamento, CFU, stato dell’esame, anno di frequenza, voto e data di verbalizzazione. Nella lista si è scelto di far visualizzare solamente il nome e il voto come noto in figura 3.11, le informazioni più importanti che uno studente vorrebbe visualizzare. Inoltre prendendo tutti i voti e i rispettivi cfu si è calcolato il voto base di laure, visualizzabile nella ActionBar dell’applicativo. 3.3.3 Controller Il Controller, come descritto in precedenza è tutto quello che riguarda la logica che avviene dopo l’interazione con l’utente e va a modificare lo stato del model e delle view. Nell’applicativo esiste solo una classe che fa parte delle categoria controllore, con il ruolo di notificare la presenza di nuovi avvisi sulla piattaforma CampusNet. Per poter implementare dei task che lavorano a lunga durata o addirittura indeterminata, si è fatto uso di un componente Android, i Service. Esistono diversi tipi di Service, ma per la tipologia di lavoro che deve svolgere all’interno dell’applicativo, si sono usati i service Started. La loro particolarità è di essere eseguiti in background indefinitamente anche se la componente che li ha avviati viene terminata. Generalmente non offrono interazione con il chiamante e proseguono finché non vengono interrotti. Inoltre i Service Started sono da prediligere per operazioni con una loro finalità indipendente dallo stato delle altre applicazioni, infatti si occuperà di scaricare gli avvisi dalla pagina Web e confrontarli con 66 3.3 Architettura dell’applicazione Implementazione e Funzionamento quelli contenuti nella base dati, notificherà con un pop-up l’avviso che non è presente nel database. Il servizio viene avviato alla prima esecuzione dell’applicazione in background. La porzione di codice mostra l’implementazione della procedura appena descritta. private void startService() { timer.scheduleAtFixedRate(new mainTask(), 60000*15, 60000*15); } private class mainTask extends TimerTask { public void run() { boolean nuovo; parseAvvisiNews = new ParseAvvisiNews(); try{ avvisiOnline = parseAvvisiNews.execute(new String[]{ "http://informatica.unipr.it/cgi-bin/" + "campusnet/avvisi.pl", "td.AVVISI-FORMAT-3 a"}).get(); if(!avvisiOnline.isEmpty()) { for(Avviso avviso : avvisiOnline) { nuovo = true; for (Avviso avviso1 : avvisiLocali) { if (avviso.getTitolo().equals(avviso1.getTitolo())) { nuovo = false; } } if(nuovo){ showNotification(); } } } }catch (Exception e) { ... } } } Come è possibile notare dal codice si è fatto uso della classe TimerTask, tramite questa è possibile schedulare un’azione, infatti la sincronizzazione di 67 3.3 Architettura dell’applicazione Implementazione e Funzionamento nuovi avvisi e il controllo viene avviata ogni quindici minuti attraverso il metodo scheduleAtFixedRate(). Quando viene invocato il metodo startService(), non viene controllata subito la presenza di nuovi avvisi ma lo scheduler partirà dopo quindici minuti al primo avvio e continuerà a controllare ogni quarto d’ora finché non verrà terminato il servizio. Gli avvisi vengono confrontati dal titolo infatti notiamo la clausola del costrutto if mediante il metodo equals() fra due stringhe: if(avviso.getTitolo().equals(avviso1.getTitolo())), se il risultato della valutazione è falso viene impostata una variabile booleana per poter entrare in un secondo costrutto if dove verrà invocata la funzione showNotification() che creerà il pop-up visualizzabile sul display dello smartphone. 68 Conclusioni Come conclusioni di questa tesi è possibile affermare di aver raggiunto gli obiettivi proposti, ovvero la possibilità di realizzare un’applicazione Android in grado di accedere ad alcune informazioni contenute in LMS. Dopo aver studiato la struttura di ogni singola piattaforma, si sono implementati componenti ad hoc in grado di ricavare informazioni dalle piattaforme scelte e gestirle nel miglior modo possibile. Le sezioni che si sono sviluppate e rese accessibili dall’applicativo sono: avvisi, news, docenti, corsi, appelli e la propria carriera universitaria. Le fonti di dati sono state acquisite dall’unione dei due LMS che il corso di informatica fa riferimento: CampusNet e ESSE3. Gli sviluppi futuri possibili su questa tesi sono: • Possibilità di condividere le informazioni visibili dall’applicativo su Google+ o Facebook; • Possibilità di iscriversi ad un appello d’esame attraverso l’applicativo; • Funzionalità per cui una volta avvenuta l’iscrizione ad un appello d’esame, viene sincronizzato sul calendario Google e il giorno precedente avvisa con una notifica pop-up; • Cercare di integrare perfettamente l’applicazione con le funzionalità di ESSE3, usando il protocollo di autenticazione CAS; • Sviluppare un eventuale porting per iOS. 69 Bibliografia [1] Learning Management System http://it.wikipedia.org/wiki/Learning_Management_System [2] CampusNet Caratteristiche, Tecnologia, Documentazione, Moduli http://www.campusnet.it/index.html [3] EasyStaff - Optimization Solvers - Gruppo ZUCCHETTI S.p.A. EasyCourse, Guida http://www.easystaff.it/it/content/easycourse [4] ESSE3 by KION a CINECA Company Documentazione, Servizi di segreteria, FAQ http://www.kion.it/it/soluzioni/esse3-servizi-segreteria-studenti [5] Google - Android Studio Project and File Structure, Android Build System, Debug and Performance https://developer.android.com/sdk/index.html [6] Jonathan Hedley Java HTML Parser, API Reference, Cookbook http://jsoup.org [7] Matteo Petrioli Paradigma di programmazione MVC http://www.html.it/pag/32833/paradigma-di-programmazione-mvc/ [8] Marco Lecce Database e SQLite in Android http://www.html.it/articoli/la-gestione-dei-database-in-android-2/ 70 Ringraziamenti Arrivato a questo punto molto importante della mia carriera sento il desidero di ringraziare tutti coloro che mi hanno aiutato e sostenuto durante questo percorso. Un primo ringraziamento va ai miei genitori per avermi concesso l’opportunità di rimanere a Parma e continuare a studiare in questa città magnifica anche dopo il loro trasferimento. Inoltre, ringrazio sentitamente il Prof. Federico Bergenti, sempre disponibile a dirimere i miei dubbi durante tutto il periodo di stesura di questo lavoro. Grazie a Gianluca Lutero per i numerosi consigli di carattere informatico durante il periodo di ricerca. Grazie a Filippo Soncini per aver contribuito con le sue doti grafiche disegnando le icone e progettando il Design dell’applicazione. Ho desiderio di ringraziare con affetto anche tutti i miei compagni di corso e in generale tutti gli amici conosciuti durante questo periodo per avermi permesso di condividere un’esperienza indimenticabile. 71