PROGETTO RUBRICA PUBBLICA ATENEO Progetto per l’esame di Web 2.0. Prof. Andrea Perego Autori: Dante Attanasio Domenico Gaglioti 1 PROGETTO RUBRICA PUBBLICA ATENEO .................................................................................................................... 1 OBIETTIVI .......................................................................................................................................................................... 3 SITUAZIONE ATTUALE ........................................................................................................................................................... 3 SOLUZIONE ........................................................................................................................................................................ 3 OVERVIEW SISTEMA............................................................................................................................................................. 4 Flusso informativo ..................................................................................................................................................... 4 Autenticazione........................................................................................................................................................... 6 Sicurezza e Denial of service ...................................................................................................................................... 6 Privacy ....................................................................................................................................................................... 7 SPECIFICHE ........................................................................................................................................................................ 7 V-Card........................................................................................................................................................................ 7 RDF/XML ................................................................................................................................................................. 10 Web Services SOAP .................................................................................................................................................. 11 Web Services REST................................................................................................................................................... 11 IMPLEMENTAZIONE ........................................................................................................................................................... 12 Mappatura database .............................................................................................................................................. 12 Funzione di ricerca nel database ............................................................................................................................. 14 Web services............................................................................................................................................................ 18 Fogli di stile XSLT ..................................................................................................................................................... 29 ONTOLOGIA ..................................................................................................................................................................... 30 Rubrica_ateneo.owl ................................................................................................................................................ 30 Istanze dell’ontologia .............................................................................................................................................. 32 EVOLUZIONI ATTUALE SITO WEB ........................................................................................................................................... 32 BIBLIOGRAFIA ................................................................................................................................................................... 34 2 Obiettivi L’obiettivo del progetto è quello di rendere disponibile, tramite protocolli standard i dati relativi ai contatti, al ruolo e alla struttura di afferenza del personale di varie tipologie che afferisce all’Università degli Studi dell’Insubria. Queste attività possono essere riassunte come la ristrutturazione della Rubrica Pubblica di Ateneo. Una delle prime applicazioni che usufruirà di tale servizio sarà una pagina del nuovo sito web d’Ateneo. Situazione attuale Attualmente i dati della rubrica di Ateneo sono memorizzati su un database Sql Server che viene interrogato e popolato da una applicazione web realizzata in proprio all’interno del centro S.I.C. con tecnologia Asp.Net e denominata Servizi On Line. Tale applicazione è usata in Ateneo per gestire le richieste e i servizi degli utenti. Tramite task pianificati denominati DTS (Data Transformation Services) di Sql Server, i dati di interesse per la rubrica pubblica vengono quotidianamente esportati sul database dell’attuale sito Web nottetempo. Questa modalità di esportazione presenta grossi svantaggi: i dati esposti sulla rubrica Internet non sono aggiornati in tempo reale, ma soltanto dopo l’esecuzione del task giornaliero. le procedure create per l’esportazione non sono riutilizzabili per altre applicazioni i dati restano “chiusi” nel database e non sono disponibili per altre applicazioni Soluzione La soluzione prevede di esportare i dati tramite Internet utilizzando un formato standard: V-CARD. I dati saranno quindi interrogabili mediante 2 web service: un web service SOAP realizzato in ASP.NET e pubblicato sul server web IIS 6, già installato nei server d’Ateneo. Questo servizio è pensato per l’integrazione di applicazioni che necessitano di protocolli di rete sicuri e affidabili come SOAP. Un web service REST realizzato sempre in ASP.NET che sia interrogabile da chiunque, anche da un semplice browser tramite un semplice URL. Entrambi i servizi restituiranno un documento RDF/XML e sarà carico del client tradurre i dati nel formato desiderato tramite fogli di stile. Al client saranno comunque forniti dei fogli di stile 3 reperibili on-line per effettuare le trasformazioni del documento RDF nei formati più comuni, tra cui XHTML, XML e ovviamente VCARD. Una delle applicazioni già note che sfrutterà questi servizi (nel dettaglio il servizio web REST) sarà una pagina web del nuovo sito di Ateneo. Overview sistema I web services dovranno fornire i dati relativi ai contatti di una persona. Verrà interrogato il database per restituire la lista di persone trovate corrispondenti al nominativo indicato dall’utente e per ognuno la lista dei suoi contatti. Per ogni utente i dati che verranno forniti saranno i seguenti: Nome e cognome Struttura di afferenza dell’Ateneo Ruolo e funzione di afferenza all’Ateneo (personale tecnico\amministrativo, docente, etc…) Lista di contatti (mail, fax, telefono) Flusso informativo La richiesta iniziale parte da un client, un qualsiasi agente che sia in grado di interrogare un web services SOAP o REST. In base al web services scelto dovrà passare come parametro una stringa contenente il nome (o parte di esso) che si desidera cercare. Sono accettate soltanto stringhe di almeno 5 caratteri, questo per evitare ricerche sull’intera rubrica che potrebbero rallentare il server. Il servizio web userà il parametro ricevuto con la richiesta per effettuare una query sul database ed estrarre i dati. Questi saranno formattati in un documento RDF/XML come da specifiche W3C (1) per il formato VCARD, integrato con le informazioni aggiuntive dell’ontologia del sistema. Il documento verrà inviato al client sfruttando lo stesso protocollo di rete usato per la richiesta iniziale. Il grafico in Figura 1 illustra il flusso informativo: 4 Figura 1 - Flusso informativo In Figura 2 è mostrato un diagramma di caso d’uso, nel quale l’attore utente effettua la richiesta che viene ricevuta dall’attore Web Services nella sua generalizzazione (REST o SOAP) ed esegue l’azione di ricerca dell’utente, a sua volta composta da 3 azioni: l’interrogazione al database, la creazione del documento RDF/XML e l’eventuale trasformazione nel formato desiderato (XHTML,XML,VCARD). Figura 2 - Diagramma casi d'uso Infine in Figura 3 è mostrata la sequenza di una possibile interrogazione dei web services: 5 Figura 3 - Diagramma di sequenza E’ importante evidenziare come, per ottimizzare le richieste al WebServices, sia sufficiente una sola chiamata per ottenere tutte le informazioni richieste contenute dal documento RDF/XML. Per ottenere poi i formati desiderati il lavoro è demandato al browser che deve soltanto scaricare i fogli di stile da un repository (che al momento corrisponde allo stesso sito del WebService ma potrebbe essere spostato in qualsiasi posto ottimizzando le risorse). Autenticazione Il servizio di visualizzazione\esportazione dei dati di rubrica non richiede un processo di autenticazione, in quanto i contatti dei dipendenti dell’Ateneo sono pubblici e attualmente pubblicati sul sito web dell’Università dell’Insubria e disponibili senza processi di autenticazione. Sicurezza e Denial of service Essendo questo servizio disponibile al pubblico è necessario predisporre dei sistemi di sicurezza che salvaguardino il servizio web da tecniche di hacking come la sql injection, il cross scripting etc… Il linguaggio di programmazione ASP.NET prevede ed implementa delle tecniche che consentono di ostacolare questi meccanismi. Analizzando per esempio la tecnica di sql injection, questa tecnica consiste nello sfruttare i parametri di input del servizio web come cavallo di troia per lanciare script o comandi dannosi per il database. Questa tecnica può essere neutralizzata con 6 un attento esame dei parametri di input, prima di usarli per comporre query SQL. ASP.NET prevede l’utilizzo di oggetti definiti Parameter, in cui vengono effettuati controlli sulla tipologia del parametro (intero, date time, stringa etc…) e per i parametri di tipo stringa vengono individuati pattern di stringhe potenzialmente pericolosi e neutralizzati. Per quanto riguarda invece Denial of Service, questa è una tecnica del tutto diversa, il cui obiettivo è quello di rendere il servizio web inutilizzabile sovraccaricandolo di richieste in modo che il server esaurisca le risorse disponibili per soddisfarle tutte e vada quindi in crash. Anche in questo caso, l’applicazione ASP.NET prevede tecniche per evitare questo tipo di attacchi (come specificato nella documentazione msdn (2) ). Per esempio: Le richieste possono essere limitate in dimensione (default 4Mb). Per ogni richiesta di un client, viene controllato che questo sia ancora connesso prima di inserire in coda la richiesta. Questo consente di evitare che un hacker possa inviare una serie di richieste simultanee e poi si disconnetta I tempi di esecuzione di una richiesta hanno un timeout configurabile. Questo consente di evitare che una richiesta vada in loop occupando tutte le risorse del server Privacy Tutti i dati esportati dal servizio web non contengono dati sensibili, quindi non ci sono particolari problemi di privacy per la diffusione su Internet tramite i servizi web. Specifiche V-Card I dati della rubrica di Ateneo sono tipi di dati molto comuni e usati in diversi ambiti e da diversi tipi di applicazioni (client di posta, pagine web, cellulari e smartphone). E’ quindi importante che il web service possa esportare tali dati adattandosi alle esigenze del client che lo interroga. Sono previsti quindi 4 formati possibili di diffusione de contatti di un utente: o V-CARD formattato tramite RDF/XML secondo specifiche W3C (1): questo consentirà a tutte le applicazioni web di ottenere i dati in un formato più comune, intuitivo e facilmente renderizzabile in ambito web mediante trasformazione XSLT in linguaggio XHTML. Questo è il formato che viene sempre restituito al browser. La trasformazione negli altri formati avviene tramite fogli di stile; 7 o o V-CARD trasformato in codice XHTML ottenuto tramite trasformazione con foglio di stile dal formato RDF. I dati dell’utente vengono rappresentati in uno specchietto riassuntivo, con una struttura minimale, pensata per essere integrata all’interno di altre applicazioni; o V-CARD formattato tramite XML: questo formato viene trasformato direttamente dal formato RDF/XML mediante un foglio di stile e ricalca in maniera fedele la struttura del documento originale, semplicemente non contiene predicati RDF. E’ pensato per applicazioni che non supportano RDF o V-CARD formattato come indicato nel documento RFC (3):utilizzando questo protocollo standard si consente lo scambio dei contatti tra varie applicazioni e vari dispositivi, soprattutto mobili. Nel RFC è definito il formato e i campi che saranno utilizzati per l’implementazione del web service. RFC 2426 (4) è stato usato per attingere le specifiche dei campi utilizzati nella nostra implementazione. Nei contatti V-CARD verranno mappati i campi presenti sulla rubrica pubblica, quindi il nome e il cognome, i dati relativi al ruolo della persona all’interno dell’Ateneo e la struttura di afferenza. Infine la lista di tutti i contatti disponibili, telefoni, mail etc… In Tabella 1 è presente la lista dei campi V-CARD che verranno utilizzati nel progetto: (i campi contrassegnati in rosso sono obbligatori, quindi devono essere sempre presenti in ogni contatto VCARD): Tabella 1 - Elenco campi formato V-CARD Nome campo Descrizione Esempio MIME DIRECTORY FEATURES Name Usato come nome da visualizzare nelle informazioni di MIME TYPE (spesso associato al campo source) Source Indica l’origine del contatto (solitamente un ldap, un database o un AD) 8 Dante Attanasio IDENTIFICATION TYPES Fn Nome completo, seguendo la Dante Attanasio semantica X.520 Common Name Attribute N Indica le varie parti del nome, Attanasio;Dante includendo prefissi o suffissi onorifici TELECOMMUNICATIONS ADDRESSING TYPE TEL;TYPE=work Un singolo numero telefonico +39 031 238 **** formattato in base allo standard X.500. Type indica che questo numero è lavorativo TEL;TYPE=work,cell Come sopra, per la fonia +39 328 ******* mobile TEL;TYPE=work,fax Come sopra, fax +39 031 238 **** EMAIL Casella di e-mail [email protected] IMPP;TYPE=sip Eventuale account sip X-SKYPE Eventuale account skype ORGANIZATIONAL TYPES TITLE Titolo della persona (inserito soltanto per il personale docente) ORG Campo fisso composta dall’organizzazione e la struttura di afferenza Esempio di contatto vcard BEGIN:VCARD VERSION:3.0 FN:DANTE ATTANASIO N:ATTANASIO;DANTE 9 Università Insubria;Centro SIC ORG:Università Insubria;CENTRO DI SERVIZI SISTEMI INFORMATIVI E COMUNICAZIONE; EMAIL:[email protected] EMAIL:[email protected] EMAIL:[email protected] EMAIL:[email protected] TEL;TYPE=WORK,CELL:3280466259 TEL;TYPE=WORK,FAX:031 238 9709 TEL;TYPE=WORK:031 238 9736 URL:www.uninsubria.it X-SKYPE:dante.attanasio X-SIP:dante.attanasio_sip END:VCARD Il formato V-CARD è un formato di testo che risulta molto leggero per la diffusione ma presenta degli svantaggi notevoli: Non è un formato strutturato Non consente di fornire una semantica delle informazioni che contiene, come relazioni tra i dati, proprietà etc… Non è un documento trasformabile in formati diversi, come invece può essere un documento XML o RDF/XML RDF/XML Il Resource Description Framework (RDF) è lo strumento base proposto da W3C per la codifica, lo scambio e il riutilizzo di metadati strutturati e consente l'interoperabilità tra applicazioni che si scambiano informazioni sul Web. L'RDF Data Model si basa su tre principi chiave: 1. Qualunque cosa può essere identificata da un Universal Resource Identifier (URI). 2. The least power: utilizzare il linguaggio meno espressivo per definire qualunque cosa. 3. Qualunque cosa può dire qualunque cosa su qualunque cosa. Il W3C ha definito anche una rappresentazione in questo formato per i contatti V-CARD, in quanto il formato testuale usato dai sistemi di posta risulta poco adatto per lo scambio tra applicazioni di vario tipo, soprattutto in ambito web, per i motivi sopra descritti. 10 I punti di forza di questa rappresentazione sono i seguenti: Formato strutturato che grazie ai predicati rdf contiene una descrizione degli oggetti rappresentati E’ una struttura dati derivata da xml ed è facilmente integrabile nel web2.0 grazie a protocolli di web services molto diffusi nella rete Ontology Web Language è un linguaggio di markup estensione di RDF usato per rappresentare la semantica di un sistema, specificando delle classi, delle proprietà e delle relazioni tra di esse. Lo scopo di OWL è quindi quello di creare delle ontologie che descrivano delle basi di conoscenza, su cui sia possibile effettuare delle deduzioni e integrarle con altre ontologie sfruttando i diffusi strumenti e protocolli di comunicazione tipici dell’ambiente web (XML, web services, http etc..). Web Services SOAP Simple Object Access Protocol è un protocollo per lo scambio di informazioni sulla rete. Il W3C ha standardizzato il tipo di servizio che sfrutta il protocollo Http per lo scambio dei pacchetti. Un oggetto SOAP si basa anch’esso sul metalinguaggio XML e ha una sua struttura divisa essenzialmente in 2 parti: Il segmento opzionale Header contiene meta-informazioni come quelle che riguardano il routing, la sicurezza e le transazioni. Il segmento obbligatorio Body trasporta il contenuto informativo e talora viene detto carico utile, o payload. Questo deve seguire uno schema definito dal linguaggio XML Schema. Web Services REST Questo tipo di servizio web è stato introdotto per soddisfare i requisiti del più grosso “cliente” dell’applicazione in oggetto, cioè il portale di Ateneo. REST non è un vero e proprio protocollo ma è più un’architettura di rete che ha come principio base il concetto di risorsa (fonti di informazioni), a cui si può accedere tramite un identificatore globale (un URI). Per utilizzare le risorse, le componenti di una rete (componenti client e server) comunicano attraverso una interfaccia standard (ad es. HTTP) e si scambiano rappresentazioni di queste risorse (il documento che trasmette le informazioni). Nel nostro caso il protocollo utilizzato per la comunicazione è proprio HTTP e la risorsa è un documento RDF/XML contenente i contatti di un dipendente dell’Ateneo. 11 Implementazione Mappatura database I campi del contatto V-CARD saranno mappati sul database esistente dei Servizi On Line. In Figura 4 – Schema E-R Database è specificato il diagramma completo dello schema E-R della parte di database utilizzato per la visualizzazione dei dati inerenti i contatti dell’utente. Figura 4 – Schema E-R Database Lo schema mostra i collegamenti della tabella utenti, che ovviamente contiene i dati anagrafici dell’utente. L’utente può avere delle strutture di afferenza, per ogni struttura un ruolo diverso. Infine, i Servizi On Line gestiscono le richieste dell’utente, in particolare la casella di posta 12 elettronica e le utenze telefoniche. Per entrambe sono quindi presenti delle entità specifiche che gestiscono le varie tipologie di dati e lo stato in cui si trovano. Infine è presente un’entità Contatti_usr che consente all’utente di inserire dei contatti personali. Tutte queste tabelle saranno disponibili al web services sotto forma di una vista che effettua il join tra le diverse tabelle dello schema e che è denominata come V_RUBRICA_PUBBLICA. Su questa vista verrà effettuata questa query: SELECT DISTINCT cognome,nome,ruolo FROM V_RUBRICA_PUBBLICA WHERE cognome + ' ' + nome LIKE '%?NOME%' Ogni riga di risultato rappresenta un contatto. Ogni riga contiene anche le informazioni anagrafiche dell’utente, che nel caso abbia più di un contatto sono duplicate. In Tabella 2 è visualizzato un esempio dei risultati del metodo cerca_persone indicato nel paragrafo successivo. Tabella 2 - Risultati interrogazione vista Cognome ATTANASIO Nome DANTE Ruolo Personale Matricola Id Tipo Contatto CSA utente contatto P06010 1196 Fax 031 238 9709 P06010 1196 Tel 031 238 9736 P06010 1196 Cell 328 0466259 P06010 1196 E-Mail dante.attanasio@uninsu Tecnico Amministrativo ATTANASIO DANTE Personale Tecnico Amministrativo ATTANASIO DANTE Personale Tecnico Amministrativo ATTANASIO DANTE Personale Tecnico Amministrativo 13 bria.it I campi cognome e nome saranno usati per i campi name, fn e n. Ruolo mappa il campo role. Il campo id_utente e il campo matricola_csa sono due diversi identificativi dell’utente, il primo sul database, il secondo nei sistemi di contabilità dell’Ateneo Carriere e Stipendi. Entrambi possono essere utili in possibili integrazioni con altri sistemi. Dalle altre colonee vengono estratti i vari contatti degli utenti, ed in base al campo tipo_contatto vengono tipizzati e formattati nel rispettivo campo. I tipi di contatto per cui non è prevista una mappatura verranno ignorati. Funzione di ricerca nel database Entrambi i web services implementano una funzione principale che, data una stringa, effettua la ricerca sul database con la query sopra specificata. Il risultato della query viene quindi formattato in codice RDF/XML come specificato nei paragrafi seguenti. String Cerca_persone(string nome):, passando come parametro una stringa contenente il nome (o una sua parte) restituisce un documento RDF/XML (sempre di tipo stringa) contenente la lista degli utenti corrispondenti ai criteri indicati. o Parametri: nome: Il parametro passato a questo metodo sarà utilizzato come filtro sui campi nome e cognome dell’utente nel database. Deve avere almeno 5 caratteri. Nella prima versione del progetto il numero di parametri si limita al nome, ma in versioni successive si possono prevedere ulteriori filtri, per esempio sulla struttura di afferenza o sul ruolo della persona (per esempio Docente o Personale Tecnico Amministrativo). o Return value: E’ un documento XML/RDF che contiene la lista degli utenti corrispondenti ai criteri indicati nel parametro con la lista di tutti i dati e di tutti i contatti dell’utente. La funzione è stata realizzata mediante ASP.NET e il seguente è il codice che genera il documento RDF/XML: //restituisce un documento XML con la lista degli utenti corrispondenti al pattern indicato public XmlDocument searchUsers(string name,string struttura_par, string id_utente_par) { //effettua la connessione al database SqlCommand cmd = conn.CreateCommand(); SqlCommand cmd2 = conn.CreateCommand(); 14 name = name.ToLower(); XmlDocument x = new XmlDocument(); DataSet ds = new DataSet(); name name name name = = = = name.Replace("'", "''"); name.Replace(";", ""); name.Replace(",", ""); name.Replace("\"", ""); //query che effettua la ricerca degli utenti sulla vista v_rubrica_pubblica cmd.CommandText = "SELECT DISTINCT id_utente,matricola_csa,cognome,nome,ruolo,tipo_contatto,contatto,struttura,indirizzo FROM V_RUBRICA_PUBBLICA "; string and=" WHERE "; //if (id_utente_par != "") //{ // cmd.CommandText += and + " id_utente=" + id_utente_par; //} //else //{ if (name != "") { cmd.CommandText += and + " cognome + ' ' + nome LIKE @nome"; and = " AND "; } //if (struttura_par != "") //{ // cmd.CommandText += and + " struttura LIKE '%" + struttura_par + "%'"; // and = " AND "; //} //} cmd.CommandText+=" order by id_utente,tipo_contatto,contatto"; SqlParameter par_nome = new SqlParameter("@nome", DbType.String); par_nome.Value = "%" + name + "%"; cmd.Parameters.Add(par_nome); SqlDataAdapter da_emp = new SqlDataAdapter(cmd); try { conn.Open(); //inizializzo il file di risposta caricando un file xml di template x.Load(Server.MapPath(template)); //inizializzo le variabili string id_utente = "-1"; string matricola_csa = ""; string cognome = ""; string nome = ""; string struttura = ""; string ruolo = ""; string tipo_contatto = ""; string contatto = ""; string indirizzo = ""; XmlNodeList nodi = x.GetElementsByTagName("rdf:RDF"); XmlNode root = nodi.Item(0); XmlNode user = x.CreateElement("Employee");//istanzio user per primo utilizzo int users = -1; string[] strutture=new string[5]; int i_strutture = 0; 15 //carico la lista delle struttura da_emp.Fill(ds, "employee"); for (int i = 0; i < ds.Tables["employee"].Rows.Count; i++) { if (id_utente != ds.Tables["employee"].Rows[i]["id_utente"].ToString()) { //incremento il contatore users++; //resetto i contatori i_strutture = 0; strutture = new string[5]; //immagazzino i nuovi dati dell'utente cognome = ds.Tables["employee"].Rows[i]["cognome"].ToString().Trim().Replace("'","''"); nome = ds.Tables["employee"].Rows[i]["nome"].ToString().Trim().Replace("'", "''"); bool isStruttura = cognome.Contains("generici"); if (isStruttura) cognome = ""; struttura = ds.Tables["employee"].Rows[i]["struttura"].ToString().Replace("'", "''").Replace(" ", "%20"); ruolo = ds.Tables["employee"].Rows[i]["ruolo"].ToString(); if (isStruttura) { ruolo = "Struttura"; } tipo_contatto = ds.Tables["employee"].Rows[i]["tipo_contatto"].ToString(); contatto = ds.Tables["employee"].Rows[i]["contatto"].ToString(); indirizzo = ds.Tables["employee"].Rows[i]["indirizzo"].ToString(); id_utente = ds.Tables["employee"].Rows[i]["id_utente"].ToString(); matricola_csa = ds.Tables["employee"].Rows[i]["matricola_csa"].ToString(); //creo il tag per il nuovo utente con l'about rdf user = x.CreateElement("Employee",NAMESPACE_LOCAL); XmlAttribute a = x.CreateAttribute("rdf","about",NAMESPACE_RDF); //a.Value = nome + "%20" + cognome; a.Value = matricola_csa; user.Attributes.Append(a); root.AppendChild(user); XmlNode id_user = x.CreateElement("id_user",NAMESPACE_LOCAL); id_user.InnerText = id_utente; user.AppendChild(id_user); XmlNode m_csa = x.CreateElement("matricola_csa", NAMESPACE_LOCAL); m_csa.InnerText = matricola_csa; user.AppendChild(m_csa); //creo i tag dei dati anagrafici vcard:fn,vcard:n (family e given name) XmlNode fn = x.CreateNode(XmlNodeType.Element, "v", "fn", NAMESPACE_VCARD); fn.InnerText = nome + " " + cognome; user.AppendChild(fn); 16 XmlNode fnn = x.CreateNode(XmlNodeType.Element, "v", "n", NAMESPACE_VCARD); XmlNode rdf = x.CreateNode(XmlNodeType.Element, "rdf", "Description", NAMESPACE_RDF); XmlNode n = x.CreateNode(XmlNodeType.Element, "v", "family", NAMESPACE_VCARD); n.InnerText = cognome; rdf.AppendChild(n); n = x.CreateNode(XmlNodeType.Element, "v", "given", NAMESPACE_VCARD); n.InnerText = nome; rdf.AppendChild(n); fnn.AppendChild(rdf); user.AppendChild(fnn); //get struttura //user.AppendChild(getStruttura(x,struttura,indirizzo,ruolo)); //strutture[i_strutture++] = struttura; //inserire is enrolled to n = x.CreateElement("isEnrolledTo",NAMESPACE_LOCAL); a = x.CreateAttribute("rdf","resource",NAMESPACE_RDF); a.Value = struttura; n.Attributes.Append(a); user.AppendChild(n); //se la struttura non è stata inserita, inserirla XmlNode s = getStruttura(x, struttura, indirizzo, ruolo); if (s != null) { root.AppendChild(s); } strutture[i_strutture++] = struttura; //aggiungo il primo contatto user.AppendChild(getContatto(x, tipo_contatto, contatto)); } else { //se la struttura è diversa ne inserisco un altro isEnrolledTo e faccio un altro check bool uguale=false; struttura = ds.Tables["employee"].Rows[i]["struttura"].ToString().Replace("'", "''").Replace(" ", "%20"); for (int j = 0; j < strutture.Length; j++) { if (strutture[j] != null) { if (strutture[j] == struttura) { uguale = true; break; } } } if (!uguale) { ruolo = ds.Tables["employee"].Rows[i]["ruolo"].ToString(); indirizzo = ds.Tables["employee"].Rows[i]["indirizzo"].ToString(); 17 //inserire is enrolled to XmlNode n = x.CreateElement("isEnrolledTo",NAMESPACE_LOCAL); XmlAttribute a = x.CreateAttribute("rdf", "resource", NAMESPACE_RDF); a.Value = struttura; n.Attributes.Append(a); user.AppendChild(n); //se la struttura non è stata inserita, inserirla XmlNode s = getStruttura(x, struttura, indirizzo, ruolo); if (s != null) { root.AppendChild(s); } strutture[i_strutture++] = struttura; } //ricarico i dati del contatto seguente tipo_contatto = ds.Tables["employee"].Rows[i]["tipo_contatto"].ToString(); if (contatto != ds.Tables["employee"].Rows[i]["contatto"].ToString()) { //se il contatto è diverso da quello precedente lo aggiunge //questo controllo consente di evitare il problema per cui, lato database, i contatti venivano //duplicati se l'utente aveva più afferenze contatto = ds.Tables["employee"].Rows[i]["contatto"].ToString(); //aggiungi gli ulteriori contatti user.AppendChild(getContatto(x, tipo_contatto, contatto)); } } } } catch (Exception ex) { //intercetto eccezioni, in caso di errori. Popolare un file di log } finally { //chiudo l'ultimo contatto e chiudo il file da_emp.Dispose(); ds.Dispose(); conn.Close(); } return x; } Web services L’implementazione dei 2 tipi di web services è praticamente identica, cambia soltanto la modalità di connessione al servizio. Il web services SOAP è interrogabile da un client compatibile all’indirizzo http://w3.ateneo.uninsubria.it/InsubriaWebServices/rubrica.asmx 18 Il client dovrà aprire una socket, connettersi al servizio web SOAP del quale potrà vedere i metodi esposti, quindi potrà chiamare il metodo e passare il parametro. Infine otterrà un documento RDF/XML che verrà passato all’applicazione che ha lanciato il client SOAP e che potrà formattare il documento sfruttando il foglio di stile xslt disponibile on-line oppure trasformandolo con un foglio di stile xslt personalizzato. Il web service REST invece non necessita di una socket di connessione, bensì è sufficiente passare il parametro “name” a questo URI: http://w3.ateneo.uninsubria.it/InsubriaWebServicesRest/rubrica.aspx?name=[parametro] In Figura 5 è mostrato il risultato di una chiamata usando come parametro il pattern “Attanasio” : Figura 5 - Esempio ricerca con un singolo risultato Il documento RDF/XML, se non specificato con altri parametri illustrati nei paragrafi seguenti,trasforma il documento in una pagina XHTML usando il foglio di stile on-line descritto in seguito. Inserendo “attan” anziché “attanasio” si ottengono 2 risultati che vengono visualizzati come mostrato in Figura 6: 19 Figura 6 - Esempio ricerca con più di 1 risultato Il codice XHTML ottenuto è volutamente minimale, in quanto questa visualizzazione serve soltanto per avere un risultato leggibile per utenti o applicazioni che non usano questo web service integrato in altre applicazioni. Inoltre, il codice generato può facilmente essere riutilizzato da altre applicazioni per integrare questi semplici specchietti all’interno della propria struttura XHTML (come avviene per il portale di Ateneo mostrato in Figura 7 ). 20 Figura 7 - Risultato ricerca integrato con il sito di Ateneo Il foglio di stile usato per la trasformazione XHTML è il seguente: http://w3.ateneo.uninsubria.it/InsubriaWebServicesRest/rubrica.xslt A sua volta il foglio di stile usa un foglio di stile CSS per la visualizzazione dei contenuti ed è disponibile anch’esso on-line a questo indirizzo: http://w3.ateneo.uninsubria.it/InsubriaWebServicesRest/css/1DefaultSkin.css E’ però possibile per l’utente ottenere il codice RDF/XML senza che siano applicate trasformazioni; per fare ciò è sufficiente aggiungere all’URI sopra indicata il parametro rdf=1 come nel seguente esempio: 21 http://w3.ateneo.uninsubria.it/InsubriaWebServicesRest/rubrica.aspx?name=attanasio&rdf=1 ottenendo così il documento RDF mostrato nello specchietto seguente: <rdf:RDF xml:base="http://w3.ateneo.uninsubria.it/InsubriaWebServicesRest/rubrica.aspx?name="> <Employee rdf:about="P006010"> <id_user>1196</id_user> <matricola_csa>P006010</matricola_csa> <v:fn>DANTE ATTANASIO</v:fn> <v:n> <rdf:Description> <v:family>ATTANASIO</v:family> <v:given>DANTE</v:given> </rdf:Description> </v:n> <isEnrolledTo rdf:resource="CENTRO%20DI%20SERVIZI%20SISTEMI%20INFORMATIVI%20E%20COMUNICAZIONE"/> <v:email> <rdf:Description> <rdf:value>[email protected] </rdf:value> </rdf:Description> </v:email> <v:email> <rdf:Description> <rdf:value>[email protected]</rdf:value> </rdf:Description> </v:email> <v:email> <rdf:Description> <rdf:value>[email protected]</rdf:value> </rdf:Description> </v:email> <v:email> <rdf:Description> <rdf:value>[email protected]</rdf:value> </rdf:Description> </v:email> <v:tel> <rdf:Description> <rdf:value>031 238 9709</rdf:value> <rdf:type rdf:resource="http://www.w3.org/2001/vcard-rdf/3.0#work"/> <rdf:type rdf:resource="http://www.w3.org/2001/vcard-rdf/3.0#fax"/> </rdf:Description> </v:tel> <v:tel> <rdf:Description> <rdf:value>031 238 9736</rdf:value> <rdf:type rdf:resource="http://www.w3.org/2001/vcard-rdf/3.0#work"/> </rdf:Description> </v:tel> </Employee> <OrgUnit rdf:about="CENTRO%20DI%20SERVIZI%20SISTEMI%20INFORMATIVI%20E%20COMUNICAZIONE"> <hasEmployees rdf:resource="S300167"/> <hasEmployees rdf:resource="PX92721"/> <hasEmployees rdf:resource="P006010"/> <hasEmployees rdf:resource="P001269"/> <hasEmployees rdf:resource="P001110"/> <hasEmployees rdf:resource="PX95819"/> <hasEmployees rdf:resource="P001219"/> 22 <hasEmployees rdf:resource="P006028"/> <hasEmployees rdf:resource="P001256"/> <hasEmployees rdf:resource="P000157"/> <hasEmployees rdf:resource="P001214"/> <hasEmployees rdf:resource="P001169"/> <hasEmployees rdf:resource="P001033"/> <hasEmployees rdf:resource="P001014"/> <hasEmployees rdf:resource="P001006"/> <hasEmployees rdf:resource="P001258"/> <hasEmployees rdf:resource="P001293"/> <hasEmployees rdf:resource="P001292"/> <hasEmployees rdf:resource="P035027"/> <hasEmployees rdf:resource="P001103"/> <hasEmployees rdf:resource="P001091"/> <hasEmployees rdf:resource="P001100"/> <hasEmployees rdf:resource="P001170"/> <hasEmployees rdf:resource="P001266"/> <hasEmployees rdf:resource="P001066"/> <hasEmployees rdf:resource="P001736"/> <hasEmployees rdf:resource="P001098"/> <v:org> <rdf:Description> <v:orgname>Universita' Insubria</v:orgname> <v:orgunit>CENTRO%20DI%20SERVIZI%20SISTEMI%20INFORMATIVI%20E%20COMUNICAZIONE</v:orgunit> <v:orgaddress>Via Valleggio 11 - 22100 COMO (Piano 0) </v:orgaddress> <v:role>Personale Tecnico Amministrativo</v:role> </rdf:Description> </v:org> </OrgUnit> </rdf:RDF> Passando invece il parametro “xml=1”, si ottiene un documento XML, che può risultare più leggero e fruibile per alcune applicazioni che non supportano il formato RDF. Il browser riceve sempre un documento in formato RDF, che però tramite il foglio di stile (disponibile on-line) sotto indicato viene trasformato direttamente dal browser nel seguente documento XML <users> <user id_user="1196" name="DANTE ATTANASIO"> <id_user>1196</id_user> <matricola_csa>P006010</matricola_csa> <fn>DANTE ATTANASIO</fn> <n> <family>ATTANASIO</family> <given>DANTE</given> </n> <isEnrolledTo>CENTRO DI SERVIZI SISTEMI INFORMATIVI E COMUNICAZIONE</isEnrolledTo> <org name="CENTRO%20DI%20SERVIZI%20SISTEMI%20INFORMATIVI%20E%20COMUNICAZIONE"> <orgname>Universita' Insubria</orgname> <orgunit>CENTRO%20DI%20SERVIZI%20SISTEMI%20INFORMATIVI%20E%20COMUNICAZIONE</orgunit> <orgaddress>Via Valleggio 11 - 22100 COMO (Piano 0) </orgaddress> <role>Personale Tecnico Amministrativo</role> <hasEmployees matricola_csa="S300167"/> <hasEmployees matricola_csa="PX92721"/> 23 <hasEmployees matricola_csa="P006010"/> <hasEmployees matricola_csa="P001269"/> <hasEmployees matricola_csa="P001110"/> <hasEmployees matricola_csa="PX95819"/> <hasEmployees matricola_csa="P001219"/> <hasEmployees matricola_csa="P006028"/> <hasEmployees matricola_csa="P001256"/> <hasEmployees matricola_csa="P000157"/> <hasEmployees matricola_csa="P001214"/> <hasEmployees matricola_csa="P001169"/> <hasEmployees matricola_csa="P001033"/> <hasEmployees matricola_csa="P001014"/> <hasEmployees matricola_csa="P001006"/> <hasEmployees matricola_csa="P001258"/> <hasEmployees matricola_csa="P001293"/> <hasEmployees matricola_csa="P001292"/> <hasEmployees matricola_csa="P035027"/> <hasEmployees matricola_csa="P001103"/> <hasEmployees matricola_csa="P001091"/> <hasEmployees matricola_csa="P001100"/> <hasEmployees matricola_csa="P001170"/> <hasEmployees matricola_csa="P001266"/> <hasEmployees matricola_csa="P001066"/> <hasEmployees matricola_csa="P001736"/> <hasEmployees matricola_csa="P001098"/> </org> <email>[email protected] </email> <email>[email protected]</email> <email>[email protected]</email> <email>[email protected]</email> <tel>031 238 9736</tel> <fax>031 238 9709</fax> </user> </users> http://w3.ateneo.uninsubria.it/InsubriaWebServicesRest/rubrica_toxml.xslt L’integrazione con la pagina di ricerca del personale presente sul nuovo sito web, userà proprio questo sistema, dato che ingloberà il codice xml ottenuto dal servizio web all’interno del codice XML che viene creato runtime dal CMS di Ateneo. Infine, è possibile ottenere anche il formato VCARD, semplicemente inserendo il parametro vcard=1 in coda alla richiesta: http://w3.ateneo.uninsubria.it/InsubriaWebServicesRest/rubrica.aspx?name=attanasio&vcard=1 In questo caso il foglio di stile usato è comunque disponibile a questo indirizzo, ma la trasformazione viene realizzata lato server per consentire al browser di ricevere il documento già con un mime type corretto, anziché come semplice stringa: 24 http://w3.ateneo.uninsubria.it/InsubriaWebServicesRest/rubrica_vcard.xslt Questo foglio di stile trasforma il documento RDF/XML in un documento di tipo testo in formato VCARD, in modo che sia un oggetto che l’utente possa salvare (Figura 8) e caricare nei vari client che supportano il formato vcard (come per esempio la maggior parte dei client di posta elettronica come mostrato in Figura 9). Figura 8 - Esempio di salvataggio file vcf 25 Figura 9 - Esempio di un contatto importato in un'applicazione di Windows I web services sono entrambi realizzati in ASP.NET ed usano un codice molto simile per chiamare la funzione sopra descritta e passare il documento RDF/XML come risposta, il seguente è il codice eseguito alla chiamata della pagina del servizio REST: protected void Page_Load(object sender, EventArgs e) { if (Request.QueryString.Count > 0) { //metodo che viene chiamato al caricamento della pagina if (Request.QueryString["rdf"] != null) { //se viene passato il parametro rdf=1 carico un template che non punta a nessun file xslt e restituisce l'rdf pulito template = "template_data.xml"; } if (Request.QueryString["vcard"] != null) { //se viene passato il parametro vcard=1 carico un template xml che punta al foglio di stile rubrica_vcard.xslt template = "template_vcard.xml"; } 26 if (Request.QueryString["xml"] != null) { //se viene passato il parametro xml=1 carico un template xml che punta al foglio di stile rubrica_toxml.xslt template = "template_xml.xml"; } //se nessuno dei due precedenti è stato impostato carico il template di default che usa il foglio di stile rubrica.xslt che trasforma il documento RDF\XML in un documento XHTML string name = ""; string struttura = ""; string id_user = ""; //if (Request.QueryString["name"] != null || Request.QueryString["struttura"]!=null || Request.QueryString["id_user"]!=null) if (Request.QueryString["name"] != null && Request.QueryString["name"].ToString().Length >= 4) { //se il parametro name contiene dei dati name = ""; if (Request.QueryString["name"] != null) { name = Request.QueryString["name"].ToString(); } struttura = ""; if (Request.QueryString["struttura"] != null) { struttura = Request.QueryString["struttura"].ToString(); } id_user = ""; if (Request.QueryString["id_user"] != null) { id_user = Request.QueryString["id_user"].ToString(); } if (Request.QueryString["vcard"] != null) { Response.Clear(); Response.ContentType = "text/v-card"; Response.ContentEncoding = System.Text.Encoding.UTF32; //Response.ContentEncoding = System.Text.Encoding.i; XmlDocument doc = searchUsers(name, "", ""); XslCompiledTransform myXslTransform = new XslCompiledTransform(); myXslTransform.Load(Server.MapPath("rubrica_vcard.xslt").ToString()); XmlNodeReader reader = new XmlNodeReader(doc); myXslTransform.Transform(reader, null, Response.OutputStream); Response.AppendHeader("Content-Disposition", "attachment;filename=" + name + ".vcf"); Response.Flush(); Response.End(); return; } else { Response.Clear(); Response.ContentType = "text/xml";//imposto il mimetype if (Request.QueryString["xml"] != null) { WriteRubrica(name, struttura, id_user, Response.OutputStream, OP_SEARCH_USERS_XML); } else { WriteRubrica(name, struttura, id_user, Response.OutputStream, OP_SEARCH_USERS); 27 } Response.Flush(); Response.End(); return; } } else { risposta_errore(); } } else { risposta_errore(); } } public void WriteRubrica(string name, string struttura, string id_user, Stream stream, int type) { //XmlTextWriter ijo = (XmlTextWriter)XmlTextWriter.Create(stream); XmlWriterSettings settings = new XmlWriterSettings(); settings.Encoding = new UTF8Encoding(false); //settings.Encoding = Encoding.GetEncoding("UTF-32");//imposto encoding del file xml settings.Indent = true; settings.OmitXmlDeclaration = false; using (XmlWriter writer = XmlWriter.Create(stream, settings)) { XmlDocument doc = new XmlDocument();//crea un documento xml if (type == OP_SEARCH_USERS_XML) { doc = searchUsers(name, struttura, id_user);//richiama il metodo searchUsers che restituisce il documento RDF\XML XslCompiledTransform myXslTransform = new XslCompiledTransform(); myXslTransform.Load(Server.MapPath("rubrica_toxml.xslt").ToString()); XmlNodeReader reader=new XmlNodeReader(doc); myXslTransform.Transform(reader, writer); } else if (type == OP_PARS_NOT_VALID) { doc.Load(Server.MapPath("template_empty.xml")); doc.WriteContentTo(writer); } else { if (type == OP_SEARCH_USERS) { doc = searchUsers(name, struttura, id_user);//richiama il metodo searchUsers che restituisce il documento RDF\XML } else if (type == OP_SEARCH_STRUTTURE) { doc = getContattiStruttura(name); } else if (type == OP_LIST_STRUTTURE) { doc = getListaStrutture(); } doc.WriteContentTo(writer);//scrive il documento al writer, che è lo stream di oupput dell'oggetto Response, cioè l'oggetto che risponde alla richiesta HTTP } } } 28 Fogli di stile XSLT I fogli di stile usati nell’applicazione sono: Il file rubrica.xslt è usato per trasformare il documento RDF/XML in un documento XHTML Il file rubrica_toxml.xslt è usato per convertire da RDF/XML a XML Il file rubrica_vcard.xslt è usato per trasformare il documento RDF/XML in un file VCARD con estensione vcf. Il file rubrica_ateneo.xslt è usato per trasformare l’ontologia rubrica_ateneo.owl in un documento XHTML leggibile da un browser per gli utenti finali Rubrica.xslt Il foglio di stile rubrica.xslt, trasforma il documento RDF/XML in un documento XHTML molto semplice che presenta la lista di utenti in cui per ognuno visualizza uno specchietto con le informazioni riguardo al ruolo e alla struttura di afferenza e la lista dei contatti. Questo foglio di stile disponibile all’indirizzo http://w3.ateneo.uninsubria.it/InsubriaWebServicesRest/rubrica.xslt è la modalità di default con cui viene trasformato l’output su una richiesta al servizio web REST. Ovviamente questo foglio di stile è comunque disponibile per qualsiasi applicazione abbia un documento XML aderente alla ontologia definita. Il file con il codice XSLT è raggiungibile a questo indirizzo: http://w3.ateneo.uninsubria.it/InsubriaWebServicesRest/rubrica.xslt Rubrica_toxml.xslt Questo foglio di stile trasforma il documento RDF originario in un documento analogo ma in formato XML. Questo nasce dall’esigenza di avere, per l’integrazione con il portale di Ateneo, la lista dei contatti in formato diverso da RDF, non supportato dal cms, dato che la porzione di codice XML generata dal servizio WEB deve essere inglobata in un documento XML più ampio generato run-time dal CMS. L’intero documento XML viene poi a sua volta trasformato con dei fogli di stile lato server dal CMS. Nei fogli di stile caricati nel cms sarà presente la parte di codice necessaria alla trasformazione in XHTML definita nel file RUBRICA.XSLT. Il file rubrica_toxml.xslt è raggiungibile a questo indirizzo: http://w3.ateneo.uninsubria.it/InsubriaWebServicesRest/rubrica_toxml.xslt 29 Rubrica_vcard.xslt Questo foglio di stile converte il documento XML\RDF in un file testuale aderente allo standard VCARD. Nel caso ci siano più utenti nel documento originario, il formato v-card consente di inserire più contatti accodando le schede v-card nel file. Il file rubrica_vcard.xslt è disponibile a questo indirizzo: http://w3.ateneo.uninsubria.it/InsubriaWebServicesRest/rubrica_vcard.xslt Rubrica_ateneo.xslt Questo foglio di stile traduce il documento OWL in un documento XHTML, per renderlo leggibile agli utenti che devono consultare l’ontologia. Ontologia Rubrica_ateneo.owl L’ontologia della nostra applicazione si basa innanzitutto su un’ontologia già esistente che viene importata, cioè l’ontologia VCARD ( www.w3.org/2006/vcard/ns ). Questa ontologia descrive tutte le classi, le proprietà e le relazioni necessarie per descrivere le varie tipologie di contatti esistenti e le relative associazioni ad una persona. Abbiamo esteso questa ontologia introducendo delle proprietà e delle classi più aderenti al nostro sistema riguardanti un dipendente, definito dalla classe Employee e la sua afferenza ad una unità organizzativa del nostro Ateneo, definita dalla classe OrgUnit. In Figura 10 è mostrato il diagramma di classe per l’ontologia: 30 Figura 10 - Diagramma classe ontologia Le proprietà di queste 2 classi sono rappresentate a questo indirizzo: http://w3.ateneo.uninsubria.it/InsubriaWebServicesRest/rubrica_ateneo.owl. Nella classe Employee è definita la proprietà isEnrolledTo. Questa proprietà definisce per il soggetto Employee, il predicato isEnrolledTo, cioè l’afferenza all’oggetto, cioè una unità organizzativa. Questa proprietà ha una cardinalità minima di una unità organizzativa, cioè un dipendente deve afferire almeno ad una struttura, e non esiste invece un limite superiore. Nella classe OrgUnit è presente la proprietà inversa di isEnrolledTo, cioè hasEmployees, nella quale per il soggetto, cioè l’unità organizzativa, vale il predicato hasEmployees, cioè ha afferenza con l’oggetto, cioè un dipendente. Anche in questo caso, una struttura deve avere almeno 1 dipendente afferente, mentre non c’è limite massimo. Infine, per la classe Employee è stato definita una data properties id_user che non era definita nell’ontologia vcard e che è un attributo specifico dell’ontologia della nostra applicazione web. E’ stata inoltre aggiunta anche la proprietà matricola_csa che rappresenta la matricola del personale nel sistema di Carriere e Stipendi di Ateneo. Questo valore viene usato per istanziare l’entità Employee. Sia matricola_csa che id_user sono due valori che identificano un utente. E’ stato scelto di esportarli entrambi, in quanto possono essere molto utili come chiave per l’integrazione in vari sistemi, come per esempio per tutti i sistemi di Ateneo che usano la matricola come chiave univoca del dipendente. 31 Il file rubrica_ateneo.owl è disponibile a questo indirizzo: http://w3.ateneo.uninsubria.it/InsubriaWebServicesRest/rubrica_ateneo.owl Istanze dell’ontologia L’ontologia genera quindi delle istanze, ovvero dei documenti RDF/XML che rappresentano le proprietà e le classi dell’ontologia. L’istanza che viene generata dalla funzione sopra descritta genera un documento RDF, nel quale per ogni utente estratto dalla query, viene creata un’istanza della classe Employee. Inoltre, per ogni struttura di afferenza dell’utente viene creata un’istanza della classe OrgUnit. Quindi alla classe Employee vengono associati secondo l’ontologia VCARD tutti i contatti disponibili per quell’utente. Inoltre, viene applicata la ObjectProperty isEnrolledTo specificando (come da sintassi RDF) come attributo rdf:resource il nome dell’unità organizzativa istanziata. Infine viene specificata la Data Property “id_user” e “matricola_csa”, definita dall’ontologia della nostra applicazione. Invece, per l’istanza della struttura, vengono definiti il nome e l’indirizzo (data property dell’ontologia VCARD), infine viene applicata la proprietà hasEmployee per tutti gli utenti afferenti a questa struttura che vengono identificati nell’attributo della proprietà rdf:resource. Un codice di esempio è definito nelle pagine precedenti. Questo codice è comunque disponibile on-line effettuando qualsiasi interrogazione al web services REST e impostando come parametro aggiuntivo rdf=1, in modo che restituisca il documento RDF/XML che rappresenta una istanza dell’ontologia. Evoluzioni attuale sito web Questo sistema è stato ampiamente testato sul nuovo portale di Ateneo ed è in coda per essere migrato come servizio in produzione per le ricerche sulla rubrica pubblica di Ateneo. Ovviamente sono già previste notevoli migliorie a questo servizio, come per esempio l’ampliamento dei filtri di ricerca ad altri parametri come la struttura, un numero telefonico etc… Inoltre si sta cercando anche di integrare elementi multimediali come fotografie o altri tipi di contenuti. 32 Dal punto di vista dei client supportati si prevede di prestare molta attenzione a tutti i possibili dispositivi che possono sfruttare appieno questo tipo di servizi, soprattutto quelli mobili. Per questo motivo si è anche pensato di poter inviare i contatti in formato VCARD tramite mail\sms\mms. 33 Bibliografia 1. W3C. Representing vCard Objects in RDF. http://www.w3.org. [Online] http://www.w3.org/TR/vcard-rdf/. 2. Microsoft. Chapter 19 – Securing Your ASP.NET Application and Web Services. http://msdn.microsoft.com. [Online] http://msdn.microsoft.com/en-us/library/aa302435.aspx. 3. IETF. A MIME Content-Type for Directory Information. http://tools.ietf.org. [Online] http://tools.ietf.org/html/rfc2425. 4. —. vCard MIME Directory Profile. http://tools.ietf.org. [Online] http://tools.ietf.org/html/rfc2425. 5. Della Valle, Celino, Cerizza. SEMANTIC WEB - Dai fondamenti alla realizzazione di un'applicazione. s.l. : Pearson Addison Wesley, 2009. 6. Della Valle, Cerino, Cerizza. SEMANTIC WEB - Modellare e condividere per rinnovare. s.l. : Pearson Addison Wesley, 2008. 7. Perego, Andrea. Materiale didattico di supporto . 34