UNIVERSITÀ DEGLI STUDI DI PALERMO FACOLTÀ DI INGEGNERIA CORSO DI LAUREA MAGISTRALE IN INGEGNERIA INFORMATICA Crawl, Transform and Memorize Tesina elaborata da: Francesco Di Miceli Gabriele Maida Antonio Pellegrino Antonio Ventimiglia Professore: Prof. ing. Roberto Pirrone Tutor: Ing. Giuseppe Russo Anno Accademico 2009/2010
1. Introduzione Scopo della seguente relazione è quello di illustrare il funzionamento della Web- Application da noi realizzata nell ambito della tesina di Architetture e progetto di sistemi web. Tale Web-Application, chiamata Crawl, Transform and Memorize, ha il compito di manipolare biografie scaricate da Wikipedia, attraverso l utilizzo di un crawler e successivamente salvare le informazioni in un database. Per realizzare questo progetto è stato necessario l'utilizzo delle seguenti tecnologie spiegate durante il corso: 1. XML 2. UML 3. XPath 4. XSLT 5. XML Schema 6. DOM (Java DOM) 7. JDBC (connessione e modifica di database) 8. Servlet 9. JSP 2
2. Descrizione del progetto 2.1 Installazione Software richiesto: Cygwin, Nutch, Tomcat Per realizzare il nostro progetto è stata necessaria l installazione del Cygwin e la opportuna configurazione del nutch. Il Cygwin è un software libero che consente ai sistemi operativi Windows di operare in maniera simile ai sistemi Unix. Il crawler è anch esso un software libero, che analizza i contenuti di una rete (o di un database) in un modo metodico e automatizzato, in genere per conto di un motore di ricerca, nello specifico il nutch-0.9. La fase successiva consiste nell inserire nella cartella urls, da noi creata all interno della cartella nutch, un file di testo contenente gli url delle pagine relative alle biografie di Wikipedia che vogliamo manipolare. Una volta inseriti gli url, possiamo eseguire il crawler attraverso il seguente comando digitato per mezzo del cygwin: bin/nutch crawl cartellaurl dir cartellaoutput Al termine dell operazione otterremo una cartella, di nome cartellaoutput, contenente i file crc 1 delle pagine di nostro interesse. Per utilizzare il nutch dobbiamo integrarlo all interno del Tomcat facendo il deploy del file nutch-0.9.war. Possiamo, a questo punto, visualizzare le biografie precedentemente scaricate. Home page del nutch su TomCat 1 crc: tipico formato dei dati usato dal nutch per ricostruire le informazioni delle pagine scaricate. 3
2.2 Struttura della Web Application Diagramma di Deployment Il Web Container utilizzato per il nostro progetto è Tomcat, il quale ci consente di utilizzare la tecnologia J2EE. Inoltre include al suo interno il Web Server Apache su cui gira la nostra applicazione. Come DBMS è stato utilizzato MySQL, ma è possibile usare anche altri tipi di DBMS installando il giusto driver JDBC. Il Database è strutturato come segue: DataBase: tesina CREATE DATABASE `tesina` Tabella principale, che contiene le informazioni relative al titolo della pagina e all abstract, implementata come segue: CREATE TABLE `principale` ( `id` int(11) NOT NULL AUTO_INCREMENT, `titolo_pagina` varchar(100) NOT NULL, `abstract` text NOT NULL, PRIMARY KEY (`id`) ) Tabella contenuti, che contiene i paragrafi delle biografie con i rispettivi titoli, implementata come segue: CREATE TABLE `contenuti` ( `id_principale` int(11) NOT NULL, `nome_contenuto` varchar(100) NOT NULL, `contenuto` text NOT NULL ) 4
2.3 Sviluppo del sistema Una volta configurato il nutch e scaricate le biografie di nostro interesse, passiamo ad analizzare l applicazione realizzata, basata su quelli che sono i requisiti funzionali del progetto: - Download dei sorgenti presenti nel nutch; - Trasformazione delle biografie in un nuovo file HTML formattato in base ad un nuovo template; - Inserimento delle informazioni in un database. ed i requisiti non funzionali: - Facilità d uso; - Affidabilità; - Usabilità. Per gestire al meglio le operazioni, e garantire i requisiti non funzionali, è stato deciso di organizzare e richiamare le funzioni da una pagina HTML principale che abbiamo nominato home. Nella home vi sono i riferimenti alle tre Servlet che compongono la Web-Application e alla pagina JSP che permette l upload manuale di singoli file. Di seguito uno screenshot della home page: Home page 5
Di seguito il grafico che riassume i principali casi d uso della Web-Application: Diagramma dei casi d uso Esempio del caso d uso memorizza : Caso d uso Memorizza Attore Utente Precondizioni 1. Deve essere stato effettuato l Upload o il Download delle biografie; 2. Deve essere stata avviata almeno una trasformazione. Flusso degli eventi 1. L utente ha digitato l indirizzo della home page; 2. Il sistema visualizza un elenco delle funzionalità; 3. L utente clicca sul tasto Database. Postcondizioni 1. Il sistema memorizza le informazioni delle biografie sul database. 6
2.4 Struttura del Progetto Per avere una più semplice gestione, è stato deciso di organizzare il progetto attraverso l uso di più directory. I file da noi implementati si trovano nella cartella Tesina-Web che si affianca alla cartella contenente il nutch. A sua volta Tesina-Web si suddivide in due directory: src che contiene le servlet e WebContent che ha una struttura più complessa. All interno di quest ultima possiamo distinguere le seguenti directory e file: Input: contiene i file che andremo a prelevare dalla cache del nutch; Output: contiene i file HTML trasformati; Output2: contiene i file xml formattati per il database; Tutti i rimanenti file HTML, XSL e JSP utilizzati. Diagramma dei Package 7
2.5 Servlet e JSP Le servlet sono delle classi Java che vengono eseguite all interno di un server Web, aventi lo scopo di estenderne le funzionalità. JSP (Java Server Page) è una tecnologia Java usata per generare dinamicamente un documento HTML, fornendo anche contenuti dinamici. Le servlet del nostro progetto sono invocate tramite il metodo doget, che richiama le funzionalità da noi implementate, e che si occupa di stampare a video la risposta. 2.5.1 UrlDownload La servlet UrlDownload, attraverso il collegamento diretto alla cache del nutch, permette di prelevare tutte le pagine HTML che sono state precedentemente scaricate tramite il crawler. Questa operazione viene eseguita mediante il buffer di lettura: final InputStreamReader inputstream = new InputStreamReader(url.openStream()); final BufferedReader reader = new BufferedReader(inputStream); A questo punto possiamo creare i nuovi file XML che conterranno il sorgente delle pagine: File file = new File(filename); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file))); Successivamente andremo a salvare i file nella cartella input. Una volta creato il nuovo file XML, attraverso Java DOM, ne prendiamo il titolo, che conterrà il nome di nostro interesse e rinominiamo il file precedentemente creato. 2.5.2 Trasforma La servlet Trasforma effettua due trasformazioni. La prima trasformazione usa il file trasformatore.xsl per analizzare i file XML presenti nella cartella input e da essi creare dei nuovi file HTML, secondo il template di uscita, memorizzandoli nella cartella output. Nell implementazione del trasformatore.xsl abbiamo analizzato attentamente le pagine delle biografie di Wikipedia, notando che esse non hanno una struttura standard. Siamo comunque riusciti ad individuare le strutture comuni a tutte le biografie, utilizzando i seguenti xpath : <!--Seleziono il titolo della pagina secondo il seguente xpath --> <title> <xsl:value-of select="./body//h1[@id='firstheading']"/> </title> <!--Qui seleziono i tag <p> precedenti il primo tag <h2>, dello stesso livello, che costituiscono l'abstract --> <xsl:value-of select="./h2[1]/preceding-sibling::p"></xsl:value-of> 8
<!--Creo l'elemento img dove salvo l'immagine caratterizzante il contenuto della pagina,secondo l'xpath utilizzato di seguito --> <xsl:element name="img"> <xsl:attribute name="src"> <xsl:value-of select=".//div[@class='floatnone' or @class='thumbinner']//img/@src" /> </xsl:attribute> <xsl:attribute name="width">181</xsl:attribute> </xsl:element> <!--La prima occorrenza di un tag <ul> costituisce la lista dei paragrafi, la seleziono e la copio --> <xsl:for-each select="//node()[name()='ul']"> <xsl:if test="position()=1"> <xsl:for-each select="./node()"> <xsl:if test="name()!='text()'"> <xsl:copy-of select="." /> </xsl:for-each> </xsl:for-each> <!--Qui costruisco i paragrafi, per tutti i nodi fratelli seguenti al nodo "script" --> <xsl:for-each select="./script/following-sibling::*"> <xsl:if test="(name()!= 'table') "> <!--Se incontro un nodo <h2> ne prelevo il valore ed il suo "id", contenuto nel suo nodo figlio "span", e costruisco un nodo <h2> nella pagina di uscita con le caratteristiche selezionate --> <xsl:if test="name()='h2'"> <xsl:element name="h2"> <xsl:attribute name="id"> <xsl:value-of select="./span[@id!='null']/@id"></xsl:value-of> </xsl:attribute> <xsl:copy-of select="./span[@id!='null']"></xsl:copy-of> </xsl:element> <!--Se incontro un nodo <h3> ne prelevo il valore ed il suo "id", contenuto nel suo nodo figlio "span", e costruisco un nodo <h3> nella pagina di uscita con le caratteristiche selezionate --> <xsl:if test="name()='h3'"> <xsl:element name="h3"> <xsl:attribute name="id"> <xsl:value-of select="./span[@id!='null']/@id"></xsl:value-of> </xsl:attribute> <xsl:copy-of select="./span[@id!='null']"></xsl:copy-of> </xsl:element> 9
<!--Se incontro un nodo <h4> ne prelevo il valore ed il suo "id", contenuto nel suo nodo figlio "span", e costruisco un nodo <h4> nella pagina di uscita con le caratteristiche selezionate --> <xsl:if test="name()='h4'"> <xsl:element name="h4"> <xsl:attribute name="id"> <xsl:value-of select="./span[@id!='null']/@id"></xsl:value-of> </xsl:attribute> <xsl:copy-of select="./span[@id!='null']"></xsl:copy-of> </xsl:element> <!--Se incontro un nodo <p> ne prelevo il suo valore testuale --> <xsl:if test="name()='p'"> <xsl:value-of select="."/> <!--Nel caso in cui il nodo corrente non abbia un nome uguale a quelli presenti nei controlli, si tratta di una immagine immersa nei tag <p>, e quindi ne prendo il suo attributo "src" e lo salvo in nuovo elemento img --> <xsl:if test="(name()!='h2')and(name()!='h3') and (name()!='h4' ) and(name()!='script')and(nae()!='p')"> <xsl:if test="name()='div'"> <br /><br /> <xsl:element name="img"> <xsl:attribute name="src"> <xsl:value-of select=".//img/@src"></xsl:value-of> </xsl:attribute> </xsl:element> <!--Nota riguardante l'immagine precedentemente selezionata --> <xsl:value-of select="."></xsl:value-of> <!--Nel caso in cui il nodo sia un "div" ne faccio la copia --> <xsl:if test="name()!='div'"> <xsl:copy-of select="." /> </xsl:for-each> 10
Di seguito il codice java utilizzato nella servlet Trasforma per richiamare il trasformatore.xsl e per effettuare la trasformazione: StreamSource xsltstream = new StreamSource(new File(path+"trasformatore.xsl")); TransformerFactory factory2 = TransformerFactory.newInstance(); Transformer transformer = factory2.newtransformer(xsltstream); DOMSource domsource = new DOMSource(documentoxml); File output = new File(path+"output/"+file+".html"); StreamResult outputstream = new StreamResult(output); transformer.transform(domsource, outputstream); La seconda trasformazione utilizza Java DOM per la creazione di nuovi file XML, formattati per agevolare l inserimento delle informazioni nel database e memorizzati nella cartella output2. Per eseguire questa trasformazione utilizziamo il metodo printnodeinfo che dato il nodo corrente da analizzare, costruisce le stringhe con i valori desiderati, ed il metodo creafile che crea il file XML adatto per il funzionamento della servlet Database. Tale file verrà validato attraverso il seguente XML Schema: <xs:schema xmlns:xs="http://www.w3.org/2001/xmlschema"> <xs:element name="contenuto"> <xs:complextype> <xs:sequence> <xs:element name="nome_contenuto" type="xs:string" /> <xs:element name="paragrafo" type="xs:string" /> </xs:sequence> </xs:complextype> </xs:element> <xs:element name="pagina"> <xs:complextype> <xs:sequence> <xs:element name="titolo" type="xs:string" /> <xs:element name="abstract" type="xs:string" /> <xs:element ref="contenuto" minoccurs="1" maxoccurs="unbounded" /> </xs:sequence> </xs:complextype> </xs:element> </xs:schema> 11
2.5.3 Database La servlet Database grazie al metodo getconnection stabilisce una connessione ad un database, tramite il driver JDBC corrispondente. Class.forName("com.mysql.jdbc.Driver"); connection = DriverManager.getConnection(dbURI,userName, password); E possibile settare gli attributi della classe, secondo le specifiche del database utilizzato. Il metodo insertdb inserisce le informazioni, estratte tramite Java DOM dal file XML della cartella output2, nel database. String insert1 = "insert into principale(titolo_pagina,abstract) values (?,?)"; String insert2 = "insert into contenuti(id_principale,nome_contenuto,contenuto) values (?,?,?)"; Tali stringhe andranno a settare i preparestatement per effettuare le query. Nel caso in cui si cerchi di inserire biografie già presenti, le precedenti saranno eliminate e sostituite con quelle nuove. String select = "select id from principale where titolo_pagina =?"; String delete1 = "delete from principale where id =?"; String delete2 = "delete from contenuti where id_principale =?"; 2.5.4 Index La Index.jsp è situata all interno della cartella output. Scopo di questa JSP è di controllare se sono presenti all interno della stessa cartella dei file HTML precedentemente trasformati. In caso affermativo ha il compito di elencarli e di creare appositi link per poterli visualizzare attraverso il browser. 12
2.5.5 Upload Una maniera alternativa di inserire file all interno della cartella input è quella di fare l upload manuale tramite una form presente nella home che richiama il servizio offerto dalla pagina upload.jsp. Di seguito il diagramma delle classi: Diagramma delle classi 3. Considerazioni e Conclusioni Il progetto sviluppato, ha avuto come obiettivo la realizzazione di una applicazione Web per la manipolazione di biografie, tratte da Wikipedia. E stato necessario per l implementazione dello stesso, approfondire le conoscenze acquisite durante il corso di Architetture e progetto di sistemi Web. L esperienza del lavoro di gruppo è stata molto proficua sull aspetto riguardante l ambiente lavorativo e sull aspetto riguardante la coordinazione tra i componenti del gruppo. In conclusione il progetto realizzato può essere utile ai fini di ricerca e ulteriormente ampliato nelle sue funzionalità. 13