Relazione sulla tecnologia Giacomo Sacchetti <[email protected]> Imad Zaza <[email protected]> 22 ottobre 2006 2 Indice 1 2 Gli Web Services 1.1 Introduzione . . . . . . . . . . . . . . 1.2 World Wide Web . . . . . . . . . . . 1.3 Service Oriented Architecture . . . . 1.4 XML Web Services . . . . . . . . . . 1.4.1 Transport . . . . . . . . . . . 1.4.2 XML Base technology . . . . 1.4.3 Messaging . . . . . . . . . . . 1.4.4 Description . . . . . . . . . . 1.4.5 Composizione . . . . . . . . . 1.4.6 Ciclo di vita . . . . . . . . . . 1.4.7 Pubblicazione di un servizio 1.4.8 Scoperta di un servizio . . . . 1.4.9 UDDI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . AXIS 2.1 Introduzione . . . . . . . . . . . . . . . . . 2.2 Installazione di Axis . . . . . . . . . . . . 2.3 Architettura di Axis . . . . . . . . . . . . . 2.3.1 Struttura principale . . . . . . . . . 2.3.2 Handler e Chain . . . . . . . . . . 2.3.3 Percorso del messaggio lato server 2.3.4 Percorso del messaggio lato client 2.4 Primi passi con Axis . . . . . . . . . . . . 2.5 Web Service Deployment Descriptor . . . 2.6 Applicazioni di esempio . . . . . . . . . . 2.7 Codifica dei dati . . . . . . . . . . . . . . . 2.8 Gestione delle eccezioni . . . . . . . . . . 2.9 Il tool WSDL2Java . . . . . . . . . . . . . . 2.10 Generazione di un servizio web . . . . . . 2.10.1 Creazione dell’interfaccia . . . . . 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 7 8 8 10 12 12 13 14 15 17 18 18 19 . . . . . . . . . . . . . . . 21 21 21 23 23 24 25 26 26 29 32 35 37 37 38 38 4 INDICE 2.10.2 Creazione del WSDL . . . . . . . . . . . . . . . . . . . . . . 2.10.3 Creazione dei bindings con WDSL2Java . . . . . . . . . . . 2.11 Il servizio PasswordCollector . . . . . . . . . . . . . . . . . . . . . 40 40 42 A Web Semantico A.1 Il Web attuale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A.2 Il progetto Semantic Web . . . . . . . . . . . . . . . . . . . . . . . . 53 53 54 Introduzione Lo scopo di questa relazione è mostrare un esempio di utilizzo della tecnologia Apache Axis. Per descrivere le funzionalità offerte da questa tecnologia, sarà prima mostrata una breve panoramica sull’architettura dei Web Services, considerandola come una fase intermedia per il passaggio da Web tradizionale a Semantic Web, per poi concentrarci sulla descrizione di questa particolare soluzione, mostrando anche dei semplici esempi applicativi. La trattazione ed i relativi esempi sono stati sviluppati e testati sul sistema operativo Mac OS X 10.4 (Tiger), con server web Apache 2.2 e Tomcat 5.5.17 come application server. La versione della servlet Axis è la 1.4 (tralasciamo la definizione delle librerie collegate, i cui dettagli sono specificati nel capitolo 2). 5 6 INDICE 1 Gli Web Services 1.1 Introduzione Il concetto di integrazione è diventato negli ultimi anni un concetto fondamentale per il software. La nascita e l’enorme successo che ha riscontrato il World Wide Web, ha causato una crescita esponenziale delle esigenze di integrazione (anche in contesti diversi), per la natura dello Web stesso, cioè un sistema per lo scambio di informazioni tra agenti per mezzo di una rete. L’integrazione di software diversi ha determinato, nell’ultimo decennio, dei compromessi tra flessibilità di utilizzo e scalabilità: le soluzioni create hanno portato da un lato alla creazione di linguaggi di programmazione flessibili ma utilizzabili solo in sistemi fortemente accoppiati (ad esempio DCOM di Microsoft), dall’altro lato a sistemi debolmente accoppiati ma ad una difficile integrazione tra software, in termini di facilità di utilizzo, costi, manutenibilità (ad esempio lo standard CORBA). Gli Web Services rappresentano una soluzione importante, che trae vantaggio dallo strumento di comunicazione (finora utilizzato principalmente da utenti umani) per eccellenza: il web. Gli Web Services costituiscono inoltre una parte importante del percorso di evoluzione da Web tradizionale a Web Semantico1 . I services rappresentano una qualsiasi funzione che ha una certa utilità e possono considerarsi come componenti software riutilizzabili: possiamo combinare tali services per creare una funzione più complessa. Inoltre questi services operano in un sistema molto aperto, cioè un sistema dove l’utilizzatore di un servizio 1 Una breve descrizione del Web Semantico è riportata nell’appendice A 7 CAPITOLO 1. GLI WEB SERVICES 8 ed il fornitore del servizio possono operare su piattaforme diverse (sia software che hardware), ma sono in grado di fornire un soddisfacente livello di interoperabilità. Inoltre questo meccanismo di comunicazione è molto flessibile, in quanto il cambiamento nodo non compromette la possibilità di conoscere il suo contenuto informativo. Per questo lo sviluppo di un software Web Services non segue le metodologie di sviluppo tradizionali: la progettazione e realizzazione si basano principalmente sull’aggregazione di componenti già sviluppati da terzi. 1.2 World Wide Web Per comprendere gli argomenti che tratteremo in seguito è opportuno precisare un insieme di concetti che stanno alla base dell’architettura del World Wide Web, che indicheremo d’ora in avanti con la sigla WWW. Seguendo quanto descritto in [Web Arch], abbiamo: Agenti Persone o software che operano sul WWW (server, spider, browser, . . .). Identificatori Un URI (Uniform Resource Identifier) è un etichetta associabile a qualunque risorsa disponibile nel sistema Risorse Sono tutto ciò che è identificato da un URI Rappresentazioni Sono un insieme di formati di dato che definiscono le informazioni che descrivono lo stato di una risorsa Protocolli Sono regole che definiscono le modalità di comunicazione tra agenti Il processo di comunicazione avviene in questo modo: per conoscere lo stato di una risorsa è necessario conoscerne la locazione (l’URI), sottoponendo questa ad una particolare operazione è possibile cosı̀ ottenere una rappresentazione dello stato di una risorsa. I dati ottenuti saranno presentati all’utente finale, in funzione dei metadati associati, per mezzo di un agente. La semantica dell’informazione è attribuita dall’utente umano, gli agenti hanno solo il compito di trasferire i dati da interpretare (accade cosı̀ per il Web tradizionale e per i Web Services, per il Web Semantico ogni agenti disporrà di informazioni semantiche e regole di inferenza che gli consentiranno di capire i dati che stà trasferendo). 1.3 Service Oriented Architecture La Service Oriented Architecture (SOA) è l’evoluzione del modello classico di distributed computing: è un modello dove ogni nodo (della rete) è un entità 1.3. SERVICE ORIENTED ARCHITECTURE 9 capace di fornire servizi ad altri nodi, attraverso la pubblicazione di un’interfaccia, che gli utilizzatori possono trovare e dalla quale possono ricavare le informazioni per usufruire del servizio. Questa interfaccia consente di mostrare un insieme di funzioni utili, fornendo il nome delle operazioni, il formato dei parametri di ingresso e uscita, i protocolli per invocare tali funzioni. Esistono, in questa architettura, tre tipi di nodi: Service Provider (SP) è il fornitore del servizio, che si occupa di sviluppare funzioni ed offrirle attraverso un interfaccia omogenea Service Broker (SB) è un archivio in cui vengono collezionate le descrizioni sui servizi forniti da un certo SP Service Requestor (SR) è l’entità che richiede l’utilizzo delle funzioni di un SP Tali tipi di nodi non sono esclusivi, cioè un nodo può ricoprire più ruoli contemporaneamente. Generalmente un SP segnala ad un SB, attraverso un’operazione di publish, che è disponibile un servizio. Il SB rende disponibile questa informazione ai SR, che lo interrogano tramite una operazione di find. Un SR che ottiene la descrizione dell’interfaccia di un SP può utilizzare le funzioni tramite un’operazione di bind. Uno schema di questo modello è rappresentato nella figura 1.1. Lo scopo fondamentale della SOA è la realizzazione dell’accoppiamento debole Service Broker d Pu b Bin lish Service Provider Find Service Requestor Figura 1.1: Modello SOA (loose coupling). Come è suggerito in [Hao He], esistono due principali problemi nella realizzazione di un’applicazione che si prefigge il riuso di componenti: CAPITOLO 1. GLI WEB SERVICES 10 le dipendenze reali e le dipendenze artificiali. Ad esempio, chi viaggia spesso oltreoceano e vuol usare il proprio notebook, ha la dipendenza reale della corrente elettrica ed la dipendenza artificiale dell’adattatore di corrente. Lo scopo della SOA non è eliminare completamente le dipendenze artificiali, ma ridurle al minimo, ottenendo cosı̀ l’accoppiamento debole e lasciando inalterate le dipendenze reali. Volendo fare un esempio dell’architettura SOA nella vita reale, possiamo pensare ad un lettore CD, che fornisce il servizio di riproduzione dei CDROM; questo lettore CD è dotato di un interfaccia dotata di alcune funzionalità: play, stop, pause, ... e questa stessa interfaccia è presente anche in altri lettori CD, in modo che sia possibile cambiare il lettore (o anche il supporto) ed ottenere lo stesso servizio. Per raggiungere lo scopo di loose coupling sono introdotti due vincoli sull’architettura: Generalità delle interfacce le interfacce sono semplici, contengono informazioni strutturare sulle operazioni offerte, senza dettagli semantici Messaggi descritti non prescrittivi I messaggi sono vincolati nella struttura da uno schema estendibile che è contenuto nell’interfaccia, non indicano il comportamento del sistema. 1.4 XML Web Services La scelta del Web come infrastruttura per la realizzazione degli Web Services non è solamente giustificata dalla sua semplicità e diffusione: l’introduzione di un nuovo paradigma può incontrare larghi consensi solamente se la sua introduzione è rapida ed ha costi sostenuti. In realtà il termine Web è abusato perchè il vero cardine dei Web Services è il sistema di indirizzamento globale fornito dagli URI. Riferendoci a [WSA], che è il documento di base dei WS, abbiamo che: • poichè ad ogni servizio è associato un URI, in base alle considerazione precedenti, questo è una risorsa del Web • la descrizione è scritta il XML, un linguaggio universalmente noto, humanreadable e soprattutto indipendente dal livello di presentazione • i messaggi per interagire con il servizio, i cui dettagli sono contenuti nella descrizione, sono documenti XML trasportati per mezzo di protocolli Internet (HTTP, FTP, SMTP, ...) Proprio per lo stretto legame con il linguaggio XML, parleremo in seguito di XML Web Service. Per quanto riguarda le caratteristiche del servizio, quelle di 1.4. XML WEB SERVICES 11 base per realizzare un WS queste sono, come descritto in precedenza, lo scambio di messaggi, la descrizione del servizio, la pubblicazione e scoperta della descrizione di un servizio. Tuttavia, al fine di agevolare la comunicazione in particolari contesti, tali caratteristiche sono solitamente estese ed, in particolare, possono essere presenti le seguenti: Gestione delle transazioni Una transazione è composta da una serie di messaggi e, nel caso in cui uno di questi non superi qualche vincolo, è da considerarsi nulla tutta la sequenza e conseguentemente la transazione è fallita Rielable messaging Un messaggio deve essere ricevuto una sola volta dal destinatario. Nel caso in cui il messaggio vada perduto, deve esistere un meccanismo per richiedere automaticamente al mittente il re-invio, senza coinvolgere l’applicazione Autenticazione dei messaggi Deve essere possibile stabilire in modo certo il mittente del messaggio Confidenzialità ed integrità dei messaggi Se è necessario i messaggi devono essere cifrati, in modo che siano disponibili solo per il legittimo destinatario. Caching È preferibile poter conservare una copia dei messaggi in modo da migliorare le performance Correlazione Un messaggio deve poter essere collegabile con altri relativi allo stesso flusso informativo. Message routing Un messaggio può seguire percorsi diversi in base allo stato della rete Gestione delle sessioni Un messaggio deve essere considerato valido in un determinato lasso di tempo Gli XML Web Services costituiscono una particolare istanza della SOA: le interfacce ed i servizi sono espressi tramite un opportuno linguaggio XML che soddisfa la genericità e l’estendibilità. Allo stesso modo i messaggi sono espressi tramite un opportuno XML, in modo da soddisfare il vincolo description not prescription. La struttura degli XML Web Services può essere schematizzata come mostrato in figura 1.2. In riferimento a questo schema, ogni protocollo o linguaggio è da considerarsi aperto, nel senso che a parte i primi due livelli (transport e XML Base) gli altri sono standard de facto, adottati in seguito alle proposte fatte dai maggiori produttori di software. Analizziamo adesso le proposte fatte per ciascun livello. CAPITOLO 1. GLI WEB SERVICES Management Description Messaging SOAP XML Base Technology Transport (HTTP, FTP, ...) Security { Aggregation { 12 Figura 1.2: XML Web Services 1.4.1 Transport In questo layer sono considerati gli aspetti propri della trasmissione dei messaggi, tramite l’uso di alcuni protocolli. Non esiste alcuna limitazione per i protocolli di rete utilizzati, è sufficiente che il flusso di esecuzione continui a seguire il modello publish - find - bind. Quello che si vuol adottare è l’indipendenza dal canale di comunicazione, per cui protocolli come SSL o JMS non sono indicati: si preferisce agire direttamente sul linguaggio XML. Lo standard de facto è HTTP. 1.4.2 XML Base technology Con questo termine si vuol indicare che XML ha un ruolo essenziale per ogni livello sovrastante, quindi ogni informazione o proprietà da esprimere và codificata in XML. Viene pertanto sfruttata la funzionalità di marshalling dell’XML: le informazioni strutturate sono convertite in un testo in formato Unicode, in modo da poter scambiare informazioni tra sistemi eterogenei indipendentemente della codifica utilizzata; una volta ricevuto il dato, ogni nodo compie un operazione di unmarshall, riportando i dati alla propria codifica. L’elaborazione dell’XML non è vincolata a particolari schemi, cioè ogni sistema può decidere autonomamente come trattare i dati XML. 1.4. XML WEB SERVICES 1.4.3 13 Messaging Come già accennato in precedenza, la comunicazione dei Web Services si basa fondamentalmente sullo scambio di messaggi, utilizzando la codifica XML. Nonostante qualsiasi testo in XML possa essere considerato un messaggio, è opportuno dare una struttura ai messaggi, in modo che l’interazione tra servizi ed utilizzatori sia possibile senza dover progettare ogni volta i messaggi. Lo standard di fatto in questo livello è dunque SOAP (Simple Object Access Protocol). SOAP Il Simple Object Access Protocol è lo strumento largamente più utilizzato per rappresentare messaggi XML. Esistono varie versioni di questo protocollo, che hanno notevoli differenze l’una dall’altra, ma nella presente trattazione ci riferiremo all’ultima versione (la 1.2). Possiamo pensare al meccanismo SOAP come ad una busta (envelope), composta da un’intestazione opzionale ed un contenitore in cui inserire dati e metadati da comunicare, ed il tutto codificato in XML. Ogni busta è atomica, cioè contiene al proprio interno tutto quello di cui necessita per interpretare i dati trasportati. Una comunicazione tra nodi SOAP è SOAP Envelope SOAP Header SOAP Body Figura 1.3: Struttura messaggio SOAP costituita dalla trasmissione di una busta da un nodo mittente ad un nodo destinatario, detto anche ultimate receiver, per distinguerlo dagli intermediari SOAP, che sono i nodi in grado di processare parti del messaggio alla scopo di fornire funzionalità aggiuntive. In particolare un intermediario riceve un messaggio SOAP e lo inoltra, eventualmente riscrivendo alcune parti dell’header, ma non CAPITOLO 1. GLI WEB SERVICES 14 modificando il body. Il ruolo e le funzionalità degli intermediari non sono definite nel protocollo SOAP, viene cosà lasciato spazio libero ad estensioni. Una caratteristica che è importante sottolineare per SOAP è il binding framework, che stabilisce una serie di vincoli che il protocollo di trasporto deve rispettare per trasmettere i messaggi SOAP. 1.4.4 Description La descrizione è l’attività il cui obiettivo è informare un possibile utilizzatore sul funzionamento e sulle caratteristiche del servizio. Tale descrizione, per la sua complessità, può essere definita in livelli. cosı̀ come mostrato nelle figura 1.4. Il primo livello ha l’obiettivo di descrivere l’interfaccia da cui ricavare le Description Business Level Agreements Service Level Agreements Composition Orchestration Presentation Policy Implementation Description Interface Description XML Schema Figura 1.4: Description informazioni necessarie per utilizzare un servizio. Il linguaggio de facto per questa attività e’ WSDL (Web Service Description Language). WSDL Il WSDL divide l’interfaccia del servizio in due componenti logiche distinte: la Service Interface Definition e la Service Implementation Definition. La prima descrive il tipo di servizio come una definizione di una classe in OOP, la seconda è un’implementazione completa di tale classe. 1.4. XML WEB SERVICES 15 Interface Description Service Implentation Definition Port Service Service Interface Definition Binding Port Type Message Type Figura 1.5: wsdl Service Interface Definition La definizione dell’interfaccia astratta è fornita per mezzo di: wsdl:portType che definisce le operazioni del servizio wsdl:message che definisce gli XML dei messaggi semplici wsdl:types che definisce i tipi XML complessi dei messaggi wsdl:binding che definisce il rapporto tra messaggi e trasporto Service Implementation Definition La definizione dell’implementazione è fornita da wsdl:service che è una collezione di elementi wsdl:port wsdl:port che è un elemento che rappresenta il legame tra un URI ed un wsdl:binding 1.4.5 Composizione È stato accennato nei paragrafi precedenti che, nel modello SOA, un nodo potrebbe fornire il servizio di raggruppamento di servizi di altri nodi. Questo CAPITOLO 1. GLI WEB SERVICES 16 servizio è però difficilmente ottenibile mediante i meccanismi SOAP-wsdl, poichè le informazioni che essi forniscono sono state-less. Il concetto di stato di una comunicazione è importante però per le applicazione B2B: in questi ambiti abbiamo una conversazione tra agenti, cioè una scambio di messaggi in un determinato arco temporale, dotato delle proprietà ACID. In questo caso per integrazione si intende quella tra processi, cioè entità in grado di scambiare un’insieme prestabilito di messaggi con altri, secondo un’insieme di vincoli, dipendenze, regole, in modo da ottenere una sequenza significativa. È giustificata quindi l’introduzione di un livello ulteriore che fornisca la funzionalità per poter conoscere lo stato della conversazione e di descrivere il comportamento di un processo. Tale linguaggio avrà ovviamente sintassi XML e deve permettere di: • definire una sequenza • stabilire l’ordine di invio e ricezione dei messaggi • determinare l’inizio e la fine di una sequenza • esprimere regole, vincoli, dipendenze, relazioni tra messaggi • fornire visione globale del servizio solo in base al flusso di messaggi La soluzione più utilizzata in questo momento è BPEL4WS. L’utilizzo di questo tipo di linguaggi non ha chiari impatti nel mondo dei WS, poichè non rientra nella categoria delle funzionalità basic. Un codice scritto in BPEL4WS è destinato ad essere eseguito su un nodo dell’architettura SOA, tramite un opportuno engine, che coordina l’attivitaà dei vari processi, attraverso lo scambio di messaggi. Ogni processo BPEL è ovviamente un servizio, dotato di interfaccia wsdl. I processi sono suddivisibili in: Astratti specificano la sequenza dei messaggi Eseguibili specificano come un partecipante si comporti durante un fase del protocollo Le attività sono classificate in: Basic come un componente interagisce con un processo esterno Structured come i componenti agiscono nel complesso 1.4. XML WEB SERVICES 1.4.6 17 Ciclo di vita Abbiamo precedentemente accennato al fatto che qualunque software è riconducibile ad un WS: è necessario solo sovrapporgli un’interfaccia in XML. Possiamo allora schematizzare il ciclo di vita di un software che implementi in WS in quattro fasi e precisamente build, deploy, run e manage.Tali operazioni possono consistere in: • creare un nuovo servizio e la relativa interfaccia mediante gli strumenti presenti nell’ambiente del SP (librerie, linguaggi di programmazione, scripts, ...) • trasformazione di un software esistente in un servizio tramite la creazione di un interfaccia • composizione di altri servizi tramite l’orchestrazione dei flussi di messaggi originati dal loro utilizzo Nello specifico di un SP, le quattro fasi consistono in: Build In questa fase si sviluppa il software e l’interfaccia Deploy In questa fare si procede alla pubblicazione dell’interfaccia ed all’integrazione con il sistema che ospita il servizio Run si raggruppano le interazioni con gli utilizzatori Manage si raggruppano le attività per la pubblicazione, l’auditing e la manutenzione del servizio Nel caso di un SR abbiamo invece: Build insieme delle operazioni per la localizzazione di un servizio, creazione del software per il binding Deploy insieme delle attività per l’esecuzione il software Run invocazione vera e propria, eventuale tempo di attesa o di servizio Manage gestione, manutenzione e controllo dei risultati ottenuti Per quanto riguarda la fase di build, possiamo individuarne quattro categorie: Green field è il ciclo di sviluppo di un WS quando non esistono né il software né l’interfaccia. Solitamente quindi si crea l’applicazione software vera e propria (che ovviamente implementa la logica del servizio nel SP), poi si crea l’interfaccia XML, cioè il file wsdl relativo al servizio appena creato (la creazione di tale file è generalmente affidata a tool automatici) CAPITOLO 1. GLI WEB SERVICES 18 Top down In questo caso abbiamo da sviluppare un’applicazione in base ad un interfaccia già definita (tipicamente è il caso di un accordo tra business partner) Bottom up In questo caso abbiamo un’applicazione potenzialmente in grado di fornire un servizio ed è sufficiente creare l’interfaccia che descrive il servizio. Meet in the middle Abbiamo sia l’interfaccia che l’implementazione, dobbiamo eseguire un processo di adattamento dei due elementi Per quello che riguarda il SR, ci sono fondamentalmente due modi per integrarsi con un servizio: Static Binding Quando il servizio è stato già selezionato prima dell’esecuzione dell’applicazione per conto della quale il SP agisce Dynamic Binding Quando il servizio è scelto a tempo di esecuzione in base alle caratteristiche espresse dalla sua interfaccia 1.4.7 Pubblicazione di un servizio Il passo successivo alla creazione della descrizione di un servizio è notificare l’esistenza dello stesso, tramite l’operazione di pubblicazione. Esistono due principali strategie per la pubblicazione: • la pubblicazione diretta, cio‘e il SR richiede direttamente al SP la descrizione del servizio offerto. In questo caso i nodi si conoscono già perché il SR è a conoscenza dell’URI per ottenere l’informazione richiesta. • utilizzare un service broker, cioè un particolare nodo, detto anche discovery agent, che offre un servizio di archiviazione delle descrizione di servizi di altri nodi della rete. 1.4.8 Scoperta di un servizio L’operazione find consiste nell’ottenere le descrizione di un servizio. È possibile distinguere due classi di scoperta di un servizio: • la scoperta a tempo di progettazione, cioè prima che avvenga l’integrazione tra nodi • la scoperta a runtime, in cui i risultati della ricerca sono le caratteristiche definite nell’interfaccia stessa 1.4. XML WEB SERVICES 19 Sicuramente l’approccio a tempo di esecuzione è più elegante, ma la limitazione espressiva del wsdl rendono il suo utilizzo improbabile, oltre al fatto che per quanto riguarda la sicurezza va gestita la fiducia tra i nodi. 1.4.9 UDDI Lo standard UDDI, Universal Description Discovery and Integration, attualmente alla terza versione, è utilizzato per la pubblicazione e scoperta di descrizioni di servizi. La sua struttura è molto simile a quella di un servizio di directory con associata una struttura dati per memorizzare descrizioni di servizi. La nascita dell’UDDI ha qualche analogia con lo sviluppo del sistema DNS: finchè il numero di servizi è limitato, gestire la pubblicazione e la scoperta possono essere svolte manualmente; quando il numero dei servizi supera un certo limite, o non è stimabile a priori, è necessario uno strumento che ci consenta di accedere alle informazioni necessarie e rilevanti. Abbiamo dunque un registro, che può essere anche replicato tra vari nodi, per fornire servizi di: Pagine bianche informazioni di base sul fornitore del servizio (e-mail, indirizzi, ...), in modo da avere identificatori del mondo reale Pagine gialle informazioni sul servizio in base alla categoria di appartenenza Pagine verdi informazioni su come accedere e come utilizzare un servizio In riferimento alla figura 1.6 un insieme di nodi, gli operator nodes, contiene una copia del contenuto del registro e vi è un meccanismo per la sincronizzazione periodica. Un elemento di questo registro ha la struttura logica che è rappresentata nella figura 1.7. Un elemento businessEntity contiene informazioni di base per individuare un servizio nel mondo reale. Ognuno di questi elementi può offrire più businessService, le infrmazioni per accedere ad essi contenute in un bindingTemplate. Ci sono fondamentalmente tre categorie di registri UDDI: Internal registry sono utilizzati all’interno di un organizzazione per integrare applicazioni interne, SP e SR appartengono allo stesso dominio amministrativo Portal registry sono utilizzati per segnalare la disponibilità di un servizio nei confronti di partners esterni, di cui si conosce il dominio di trust Marketplace registry sono utilizzati per fornire servizi verso utenti esterni, non appartenenti ad un dominio fidato CAPITOLO 1. GLI WEB SERVICES 20 UDDI Specifications Operator Node Replication + Operator Node Replication Operator Node UDDI Schema Figura 1.6: UDDI <businessEntity> - Name, contact, description - Identifiers and categories <publisherAssertion> - Relationship between two companies <businessService> - Grouping of logical services <tModel> <bindingTemplate> - Technical information of a single web service - URL access points for service - Specification implemented by web service - URL pointer to specifications Figura 1.7: UDDI Entry 2 AXIS Forniremo in questo capitolo una descrizione di Axis, illustrando i passi necessari per la configurazione e dei semplici esempi applicativi. 2.1 Introduzione Axis (Apache eXtensible Iteraction System) è un framework per la costruzione di agenti SOAP. È scritto in Java ed offre, oltre al supporto a WSDL, una serie di piccole, ma utili, funzionalità quali: un tool per la generazione delle classi Java da WSDL, un tool di monitoraggio di pacchetti TCP/IP, un server stand-alone. Axis funziona come Web Application, cioè per funzionare necessita di essere installata su un server J2EE compilant. Nel nostro caso utilizzeremo Apache Tomcat, un servlet engine del progetto Jakarta, largamente utilizzato anche in produzioni aziendali. 2.2 Installazione di Axis Il processo di installazione che illustreremo è stato realizzato sul sistema operativo Mac OS X 10.4.7 (Tiger). La versione di Tomcat installata su tale sistema operativo è la 5.5.17 ed useremo l’ultima versione stabile di Axis (al momento la 1.4). Al momento dell’avvio di Tomcat, le informazioni mostrate sono le seguenti neperobook:˜ giacomo$ sudo /Library/Tomcat/bin/startup.sh 21 CAPITOLO 2. AXIS 22 Using Using Using Using CATALINA_BASE: /Library/Tomcat CATALINA_HOME: /Library/Tomcat CATALINA_TMPDIR: /Library/Tomcat/temp JRE_HOME: /System/Library/Frameworks/JavaVM.framework/Versions/1.5/Home Per installare Axis sarà sufficiente installare la web application nella cartella CATALINA BASE/webapps. Nel nostro caso Tomcat è configurato per stare in ascolto sulla porta 8080, per cui Axis sarà raggiungibile all’indirizzo: http://localhost:8080/axis/ La pagina di Axis visualizzata al precedente indirizzo è mostrata nella figura 2.1. Per validare l’installazione di Axis è sufficiente visitare il link Validation Figura 2.1: Homepage dell’applicazione web Axis presente in tale pagina. Solitamente quello di cui si ha bisogno, perché non sono incluse in Axis, sono le seguenti librerie: • SAAJ API ( javax.xml.soap.SOAPMessage ) • JAX-RPC API ( javax.xml.rpc.Service ) • Apache-Axis ( org.apache.axis.transport.http.AxisServlet ) 2.3. ARCHITETTURA DI AXIS 23 • Jakarta-Commons Discovery ( org.apache.commons.discovery.Resource ) • Jakarta-Commons Logging ( org.apache.commons.logging.Log ) • Log4j ( org.apache.log4j.Layout ) • IBM’s WSDL4Java ( com.ibm.wsdl.factory.WSDLFactoryImpl ) • JAXP implementation ( javax.xml.parsers.SAXParserFactory ) • Activation API ( javax.activation.DataHandler ) Le librerie opzionali sono • Mail API ( javax.mail.internet.MimeMessage ) • XML Security API ( org.apache.xml.security.Init ) • Java Secure Socket Extension ( javax.net.ssl.SSLSocketFactory ) Il modo più semplice per non avere complicazioni con il CLASSPATH è collocare tali librerie nella directory CATALINA BASE/common/lib. La pagina di validazione, se le librerie sono correttamente installare, dovrebbe essere come quella nella figura 2.2. Va precisato che la visualizzazione corretta di tale pagina di validazione è una condizione necessaria ma non sufficiente. 2.3 Architettura di Axis Forniremo in questa sezione la descrizione dell’architettura di Axis, entrando anche nello specifico lavoro che compiono le classi che lo implementano. 2.3.1 Struttura principale Essendo un processore SOAP, il lavoro fondamentale di Axis è processare messaggi. Tali messaggi vengono elaborati passando per una serie di handler. Il numero e l’ordine in cui questi handler vengono invocati dipende dalla configurazione del servizio. L’oggetto che passa tra un handler e l’altro è il MessageContext. Tale oggetto contiene tutte le informazioni necessarie per l’elaborazione del messaggio stesso. Gli handler sono solitamente raggruppati in insiemi ordinati per formare una chain. CAPITOLO 2. AXIS 24 Figura 2.2: Pagina di validazione di Axis 2.3.2 Handler e Chain Una chain è una collezione di handler ed è a sua volta un handler, poichè l’interfaccia org.apache.axis.Chain estende l’interfaccia Handler (sempre del package org.apache.axis), integrandola con alcuni metodi per l’aggiunta e la rimozione degli handler, come mostrato nella figura (2.3). Ogni handler che appartiene alla chain ha la possibilità di leggere il messaggio e modificarlo prima di passarlo all’handler successivo. Alcuni handler hanno la caratteristica di avere un pivot point. Tale pivot point è un handler in cui una richiesta cessa di essere processata e inizia ad essere processata una risposta. I chain che hanno un pivot point sono anche detti targeted chain. Esistono tre di tipi di handler: Handler di trasporto sono gli handler che possono svolgere operazioni di compressione dati, autenticazione e si differenziano in base al tipo di protocollo di trasporto usato (HTTP, SMTP, . . . ). Handler globali sono handler che processano qualsiasi messaggio diretto ad Axis, qualsiasi sia il Web Service e qualsiasi sia il protocollo di trasporto usato. Handler server-specific serve per far sı̀ che l’handler venga usato solo con un 2.3. ARCHITETTURA DI AXIS 25 << interface >> Handler << abstract >> << interface >> BasicHandler Chain << concrete >> SimpleChain Figura 2.3: Handlers e Chains determinato servizio, in modo da implementare funzionalità come crittografia, autenticazione, etc. 2.3.3 Percorso del messaggio lato server Nel momento in cui arriva un messaggio SOAP sul server, questo viene letto dal TransportListener che lo inserisce in un oggetto Message. Quest’ultimo viene poi inserito in un MessageContext, un oggetto contiene anche informazioni tra cui SOAPAction e transportName, che rispettivamente indicano un parametro presente nell’header del messaggio ed il tipo di protocollo di trasporto usato. A questo punto il MessageContext viene passato alla catena handler di trasporto, che contiene una request chain, una response chain o entrambi. Se la chain di trasporto è configurata, allora il MessageContext è passato al metodo invoke() dell’handler. Dopo essere passato per la chain di trasporto, il MessageContext passa per la chain globale, se definita. Infine il MessageContext arriva alla chain server-specific che lo invierà ad un provider. Il provider, che è anch’esso un handler, si occupa della logica di codifica e background del servizio. CAPITOLO 2. AXIS 26 Figura 2.4: Percorso messaggio lato server 2.3.4 Percorso del messaggio lato client Il percorso del messaggio dal lato del client è speculare rispetto a quello del server, con la differenza che non esiste un provider (perchè non è fornito alcun servizio). Il Sender si occupa di gestire le operazioni relative al protocollo di trasporto e di inviare/ricevere messaggi. Le chain che si possono definire lato client sono le stesse definibili per il server. Figura 2.5: Percorso messaggio lato client 2.4 Primi passi con Axis Il modo più semplice per realizzare un servizio web con Axis è copiare il file sorgente Java nella cartella di Axis e rinominare il file con estensione jws. Ad esempio, se abbiamo la seguente classe: Listing 2.1: Classe di esempio 1 public class PasswordCollector { 2.4. PRIMI PASSI CON AXIS 27 private DbText db; 2 3 public String toString () { [...] } 4 5 6 7 [...] 8 9 } per avere il servizio web sarà sufficiente copiare il file PasswordCollector.java in CATALINA HOME/webapps/axis/PasswordCollector.jws e tale servizio sarà cosı̀ raggiungibile all’indirizzo: http://localhost:8080/axis/PasswordCollector.jws Richiedendo la risorsa con questo indirizzo, Axis si occuperà di compilare la classe, pubblicare il servizio e convertire le chiamate SOAP in chiamate di funzioni Java. Aggiungendo il suffisso “?WSDL” all’URI precedente Axis genererà automaticamente la specifica WSDL del servizio, per cui per l’esempio precedente avremo: Listing 2.2: WSDL Generato da Axis 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions targetNamespace="http://localhost:8080/axis/PasswordCollector.jws" xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:impl="http://localhost:8080/axis/PasswordCollector.jws" xmlns:intf="http://localhost:8080/axis/PasswordCollector.jws" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <!--WSDL created by Apache Axis version: 1.4 Built on Apr 22, 2006 (06:55:48 PDT)--> <wsdl:message name="toStringRequest"> </wsdl:message> <wsdl:message name="toStringResponse"> <wsdl:part name="toStringReturn" type="xsd:string"/> </wsdl:message> <wsdl:portType name="PasswordCollector"> <wsdl:operation name="toString"> <wsdl:input message="impl:toStringRequest" name="toStringRequest"/> <wsdl:output message="impl:toStringResponse" name="toStringResponse"/> </wsdl:operation> </wsdl:portType> CAPITOLO 2. AXIS 28 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 <wsdl:binding name="PasswordCollectorSoapBinding" type="impl:PasswordCollector"> <wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="toString"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="toStringRequest"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://DefaultNamespace" use="encoded"/> </wsdl:input> <wsdl:output name="toStringResponse"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost:8080/axis/PasswordCollector.jws" use="encoded"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="PasswordCollectorService"> <wsdl:port binding="impl:PasswordCollectorSoapBinding" name="PasswordCollector"> <wsdlsoap:address location="http://localhost:8080/axis/PasswordCollector.jws"/> </wsdl:port> </wsdl:service> </wsdl:definitions> Axis fornisce anche un package Java per poter utilizzare i servizi web dal lato client. Ad esempio per poter utilizzare la funzionalità toString del servizio PasswordCollector il codice è il seguente: Listing 2.3: Test.java 1 2 3 import org.apache.axis.client.Call; import org.apache.axis.client.Service; 4 5 6 7 8 9 10 11 12 13 14 public class Test { public static void main(String [] args) { try { String endpoint = "http://localhost:8080/axis/PasswordCollector.jws"; Service service = new Service(); Call call = (Call) service.createCall(); call.setTargetEndpointAddress(new java.net.URL(endpoint)); call.setOperationName("toString"); String ret = (String) call.invoke(new Object [] {} ); 2.5. WEB SERVICE DEPLOYMENT DESCRIPTOR System.out.println("La risposta del servizio e’: "+ret); } catch (Exception e) { System.err.println(e.toString()); } 15 16 17 18 } 19 20 29 } Come è facile vedere dal codice precedente, alle righe 10 e 11 vengono creati gli oggetti Service e Call, che sono gli oggetti standard di JAX-RPC per memorizzare i metadati sul servizio da richiamare. L’impostazione dell’endpoint URL definisce il destinatario del messaggio SOAP. Sul tipo dei parametri del metodo chiamato e sul tipo di ritorno parleremo nei paragrafi seguenti. 2.5 Web Service Deployment Descriptor I file jws sono sicuramente un modo semplice per trasformare classi Java in servizi web, ma non sempre sono la miglior scelta. Ad esempio, non sempre disponiamo del codice sorgente di un’applicazione che vogliamo rendere disponibile sul Web. Inoltre, la configurazione che possiamo specificare sul servizio è molto limitata: si pensi alla gestione dei tipi oppure ai meccanismi di sicurezza. La soluzione a questo problema è l’utilizzo dei WSDD (Web Service Deployment Descriptor). Un file WSDD è scritto in XML e contiene un insieme di direttive per indicare quali funzionalità pubblicare con Axis. Un esempio di file WSDD per pubblicare il servizio PasswordCollector potrebbe essere: Listing 2.4: Semplice file WSDD 1 2 3 4 5 6 7 8 <deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> <service name="PasswordCollector" provider="java:RPC"> <parameter name="className" value="net.nepero.portal159.passwordcollector.PasswordCollector" /> <parameter name="allowedMethods" value="*" /> </service> </deployment> In generale l’elemento service può essere costituito da: in flusso di richieste, un pivot Handler (o provider), un flusso di risposta. Per quanto riguarda il provider, in questo caso abbiamo che è java:RPC ed indica il servizio Java RPC (org.apache.axis.providers.java.RPCProvider). La classe che il provider deve instanziare è definita dal parametro chiamato className ed i parametri a cui possiamo accedere sono definiti da allowedMethods, separati da virgola oppure specificando * se si vuol dar l’accesso a tutti i metodi CAPITOLO 2. AXIS 30 pubblici. Un ulteriore parametro che possiamo specificare è scope, che serve a definire il tipo di azione che il provider deve compiere sull’oggetto Java che definisce il servizio. I possibili valori di scope e le relative azioni sono: • request: in questo caso ad ogni richiesta del servizio viene instanziato un nuovo oggetto • application: viene creato un oggetto singleton alla prima richesta ed il suo stato è condiviso alle richieste successive • session: viene creato un nuovo oggetto per ogni sessione attivata Per specificare lo scope è sufficiente inserire il parametro con nome scope tra quelli del servizio, ad esempio: Listing 2.5: File WSDD con scope 1 2 3 4 5 6 7 8 9 <deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> <service name="PasswordCollector" provider="java:RPC"> <parameter name="className" value="net.nepero.portal159.passwordcollector.PasswordCollector" /> <parameter name="allowedMethods" value="*" /> <parameter name="scope" value="request" /> </service> </deployment> Per configurare gli handler di servizio, è necessario aggiungere, nel file WSDD, un elemento handler per ognuno di essi ed un elemento requestFlow all’interno delle specifiche del servizio, per impostare l’ordine di esecuzione. Ad esempio Listing 2.6: File WSDD con service-handler 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> <handler name="log" type="java:net.nepero.portal159.log.LogHandler"> <parameter name="filename" value="login.log" /> </handler> <service name="PasswordCollector" provider="java:RPC"> <requestFlow> <handler type="log" /> </requestFlow> <parameter name="className" value="net.nepero.portal159.passwordcollector.PasswordCollector" /> <parameter name="allowedMethods" value="*" /> <parameter name="scope" value="request" /> </service> </deployment> 2.5. WEB SERVICE DEPLOYMENT DESCRIPTOR 31 In questo caso il servizio LogHandler si occuperà di monitorare le informazioni riguardanti le richieste al servizio PasswordCollector, come mostrato dal listato 2.7 (la definizione di un logger è di notevole importantanza durante lo sviluppo dello web service per fare debugging). Listing 2.7: Codice dell’handler del servizio 1 package net.nepero.portal159.log; 2 3 4 5 6 import import import import org.apache.axis.AxisFault; org.apache.axis.Handler; org.apache.axis.MessageContext; org.apache.axis.handlers.BasicHandler; 7 8 9 10 import java.io.FileOutputStream; import java.io.PrintWriter; import java.util.Date; 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 public class LogHandler extends BasicHandler { public void invoke(MessageContext msgContext) throws AxisFault { try { Handler serviceHandler = msgContext.getService(); String filename = (String)getOption("filename"); if ((filename == null) || (filename.equals(""))) throw new AxisFault("Server.NoLogFile", "Errore nella configurazione del logger.", null, null); FileOutputStream fos = new FileOutputStream(filename, true); PrintWriter writer = new PrintWriter(fos); Integer numAccesses = (Integer)serviceHandler.getOption("accesses"); if (numAccesses == null) numAccesses = new Integer(0); numAccesses = new Integer(numAccesses.intValue() + 1); Date date = new Date(); String result = date + ": servizio " + msgContext.getTargetService() + " richiesto " + numAccesses + " volte."; serviceHandler.setOption("accesses", numAccesses); writer.println(result); writer.close(); } catch (Exception e) { throw AxisFault.makeFault(e); } } } CAPITOLO 2. AXIS 32 Per poter pubblicare il servizio appena configurato con il file WSDD sono necessarie alcune operazioni ben più complesse di una semplice copia del file, come nel caso precedentemente descritto. Innanzitutto le informazioni su tutti i servizi installati sono registrate nel file di configurazione server-config.wsdd, contenuto nella cartella WEB-INF di Axis. Quindi per installare il servizio si può procedere attraverso la modifica di questo file oppure utilizzando il tool AdminClient di Axis. Per utilizzare questo tool, che è sicuramente il modo più semplice per pubblicare un servizio, è sufficiente richiamarlo da linea di comando tramite: java org.apache.axis.client.AdminClient Per poter effettuare un deploy di un servizio sarà necessario specificare come paramentro il nome del file WSDD che ne descrive la configurazione: java org.apache.axis.client.AdminClient passwordcollector.wsdd È disponibile avere la lista dei servizi attualmente installati tramite il comando java org.apache.axis.client.AdminClient list 2.6 Applicazioni di esempio Analizziamo in questo paragrafo come realizzare le applicazioni lato client, cioè i SR. Un semplice codice per interagire con il servizio echo è il seguente: Listing 2.8: Client.java 1 2 3 4 5 import import import import import org.apache.axis.Constants; java.xml.rpc.ParamaterMode; java.net.URL; org.apache.axis.client.Call; org.apache.axis.client.Service; 6 7 8 9 10 11 12 13 14 public class Client { public static void main(String [] args) { String endp = "http://localhost:8080/axis/echo.jws"; String message = "hello!"; Service service = new Service(); Call call = (Call) service.createCall(); call.setTargetEndpointAddress( new URL(endp) ); call.setOperationName("echo"); 15 16 17 call.addParameter("message", Constants.XSD_STRING, ParameterMode.IN); 18 19 20 call.setReturnType(Constants.XSD_STRING); String ret = (String) call.invoke( 2.6. APPLICAZIONI DI ESEMPIO new Object[] { message } ); System.out.println("Ho inviato: " + message + "\n"); System.out.println("Ho ricevuto: " + ret); 21 22 23 } 24 25 33 } Rispetto all’esempio del paragrafo precedente, và notata alle righe 16, 17 e 18 la definizione dei tipi di dato dei parametri di input ed output che verranno poi introdotti nel messaggio SOAP che deriva dalla serializzazione dell’oggetto che rappresenta il messaggio. Avremo in questo caso: Listing 2.9: SOAP Request 1 2 3 4 5 6 7 8 9 10 <?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENV=http://schemas.xmlsoap.org/soap/envelope/ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <SOAP-ENV:Body> <ns1:echo xmlns:ns1="http://www.nepero.net"> <message xsi:type="xsd:string">hello!</message> </ns1:echo> </SOAP-ENV:Body> </SOAP-ENV:Envelope> E la risposta del server sarà: Listing 2.10: SOAP Response 1 2 3 4 5 6 7 8 9 10 <?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENV=http://schemas.xmlsoap.org/soap/envelope/ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <SOAP-ENV:Body> <ns1:echoResponse xmlns:ns1="http://www.nepero.net"> <response xsi:type="xsd:string">hello!</response> </ns1:echoResponse> </SOAP-ENV:Body> </SOAP-ENV:Envelope> Analizziamo adesso un esempio più complesso di interazione tra client e web service che fà uso anche degli header SOAP. La gestione è più complessa perché è necessario far uso delle API per gestire dati in XML. Ad esempio, per creare il messaggio: Listing 2.11: SOAP con header 1 2 <?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" CAPITOLO 2. AXIS 34 3 4 5 6 7 8 9 10 11 12 13 14 15 16 xmlns:SOAP-ENV=http://schemas.xmlsoap.org/soap/envelope/ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <SOAP-ENV:Header> <x:Authentication> <x:login>zaza</x:login> <x:password>zaza</x:password> </x:Authentication> </SOAP-ENV:Header> <SOAP-ENV:Body> <ns1:echo xmlns:ns1="http://www.nepero.net"> <message xsi:type="xsd:string">hello!</message> </ns1:echo> </SOAP-ENV:Body> </SOAP-ENV:Envelope> Una possibile implementazione Java potrebbe essere: Listing 2.12: Esempio utilizzao SOAP Header 1 import java.net.URL; 2 3 4 5 6 7 8 9 10 11 12 import import import import import import import import import import javax.xml.parsers.DocumentBuilder; javax.xml.parsers.DocumentBuilderFactory; org.w3c.dom.Document; org.w3c.dom.Element; org.apache.axis.client.Service; org.apache.axis.client.Call; org.apache.axis.message.SOAPEnvelope; org.apache.axis.message.SOAPHeaderElement; org.apache.axis.message.RPCElement; org.apache.axis.message.RPCParam; 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public class Client { public static void main (String [] args) { String endp = "http://localhost:8080/axis/echo.jws"; String message = "hello!"; // Creazione XML DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); Document doc = db.newDocument(); // Costruisco gli elementi <authentication>, <login> e <password> Element auth = doc.createElementNS("http://www.nepero.net", "Authentication"); Element login = doc.createElementNS("http://www.nepero.net", "login"); Element password = doc.createElementNS("http://www.nepero.net", "password"); // Assemblo gli elementi login.appendChild( doc.createTextNode("zaza") ); 2.7. CODIFICA DEI DATI 35 password.appendChild( doc.createTextNode("zaza") ); auth.appendChild(login); auth.appendChild(password); // Creo l’header SOAPHeaderElement she = new SOAPHeaderElement(auth); // Costruisco un messaggio SOAP SOAPEnvelope envelope = new SOAPEnvelope(); // Aggiungo l’header al messaggio envelope.addHeader(she); // Creo la codifica RPC del messaggio e della chiamata del metodo // e lo aggiungo al body del messaggio SOAP Object [] params = new Object [] { message }; RPCElement rpcCall = new RPCElement("http://www.nepero.net", "echo", params); envelope.addBodyElement(rpcCall); // Uguale all’esempio di client senza header Service service = new Service(); Call call = (Call) service.createCall(); call.setTargetEndpointAddress( new java.net.URL(endp)); // Effettuo la chiamata passando l envelope SOAPEnvelope respEnv = call.invoke (envelope); // Recupero il risultato dal messaggio SOAP di risposta RPCElement respRPC = (RPCElement) respEnv.getFirstBody(); RPCParam result = (RPCParam) respRPC.getParams().get(0); System.out.println("Ricevuto: " + (String) result.getValue()); 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 } } 2.7 Codifica dei dati Una aspetto molto importante nell’utilizzo dei Web Services ed in particolare di Axis è la codifica dei dati, cioè la rappresentazione dei parametri in ingresso ed uscita di un servizio. In Axis, i dati vengono mappati usando le regole definite nella specifica JAX-RPC e la tabella 2.1 ne mostra un riassunto. Per quanto riguarda le collezioni di Java (Vector, ArraList, . . . ) non esistono serializzatori o deserializzatori specifici e quindi l’unico modo per inviare tali collezioni è usare gli array di SOAP. Anche per quanto riguarda i tipi definiti dall’utente, non è possibile trasferirli direttamente tramite Axis, senza prima effettuare il mapping con un serializzatore o deserializzatore. Axis fornisce una serie di serializzatori e deserializzatori il cui compito è convertire tipi Java e codificarli nello standard JAX-RPC. Uno dei serializzatori più flessibili è BeanSerializer: con questo è possibile convertire qualunque classe Java scritta seguendo lo stile dei CAPITOLO 2. AXIS 36 xsd:base64Binary xsd:boolean xsd:byte xsd:dateTime xsd:decimal xsd:double xsd:float xsd:hexBinary xsd:int xsd:integer xsd:long xsd:QName xsd:short xsd:string byte[] boolean byte java.util.Calendar java.math.BigDecimal double float byte[] int java.math.BigInteger long javax.xml.namespace.QName short java.lang.String Tabella 2.1: Mapping tra tipi XSD e Java JavaBeans. Per poter utilizzare questi serializzatori/deserializzatori è necessario specificare il mapping tra tipo e classe serializzatrice, sia lato server che lato client. Dal lato server il mapping và definito nel file WSDD, aggiungendo una voce del tipo: Listing 2.13: Bean Mapping 1 2 <beanMapping qname="ns:local" xmlns:ns="http://www.nepero.net" languageSpecificType="java:net.nepero.TestClass" /> Con questo codice è associato “ns:local” a “net.nepero.TestClass” e viceversa. Quando all’interno del messaggio SOAP viene letto un tipo con il nome “ns:local” questo sarà associato dal server a “net.nepero.TestClass” e verrùsata la classe BeanSerializer per la codifica. Per quanto riguarda il mapping dei tipi lato client, torniamo ad analizzare l’istruzione ... call.addParameter("message", Constants.XSD\_STRING, ParameterMode.IN); ... Il parametro Costants.XSD STRING è in realtà un oggetto della classe Java javax.xml.namespace.QName che rappresenta xsd:string. Axis riesce a risalire, tramite l’oggetto Constants.XSD STRING, alla classe che si occupa della serializzazione del parametro. Per serializzare un tipo è dunque necessario creare un’istanza di QName che rappresenti il nome del tipo e specificare successivamente gli oggetti che si occupano della serializzazione. Dal lato client questo si esprime attraverso il costrutto: 2.8. GESTIONE DELLE ECCEZIONI 37 ... QName qn = new QName("http://www.nepero.net", "local"); call.registerTypeMapping(net.nepero.TestClass, qn, BeanSerializerFactory.class, BeanDeserializerFactory.class); ... Un caso particolare è quello della trasformazione di una applicazione legacy1 all’architettura SOA. In questo caso si preferisce specificare i serializzatori e deserializzatori direttamente nel file WSDD. Listing 2.14: Type mapping 1 2 3 4 5 <typeMapping qname="ns:local" xmlns:ns="http://www.nepero.net" languageSpecificType="java:net.nepero.TestClass" serializer="javaClassSerializerFactory" deserializer="javaClassDeserializerFactory" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> 2.8 Gestione delle eccezioni Se il metodo lancia un eccezione che è istanza o sottotipo della classe Java java.rmi.RemoteException, questa è convertita autometicamente da Axis in un SOAP fault. In tale specifica, il valore del faultcode è il nome della classe ed il client proverà a deserializzare tale eccezione attraverso un’eccezione Java. Nel caso in cui il client non disponga di tale classe verrà usata un’istanza di java.rmi.RemoteException. Tale funzionalità è ovviamente possibile se e solo se sia lato server che lato client è disponibile Axis. Infatti, non tutte le piattaforme software dispongono del concetto di eccezione, quindi ogni client è libero di mappare i SOAP fault come ritiene più opportuno. 2.9 Il tool WSDL2Java Axis fornisce un tool, WSDL2Java, che a partire da un documento WSDL genera automaticamente stub, skeleton, tipi di dati e client ad hoc. Tale tool è richiamabile da linea di comando tramite: java org.apache.axis.WSDL.WSDL2Java descr.WSDL 1 Il sistema legacy è un sistema informatico esistente o una applicazione che continua ad essere usata poiché l’utente (tipicamente un’organizzazione) non vuole o non può rimpiazzarla. Le ragioni che inducono a mantenere sistemi legacy sono soprattutto dovute ai costi sostenuti per la loro implementazione e ai costi da sostenere per la migrazione a nuovi sistemi. (fonte wikipedia.it) CAPITOLO 2. AXIS 38 Descriviamo brevemente il comportamento si questo tool: • per ogni entry della sezione type vengono generati una classe Java dello stile JavaBean ed una classe holder se i tipi definiti sono usati come parametri di I/O • per ogni elemento portType viene generata un interfaccia Java come interfaccia del servizio • per ogni binding viene generata una classe stub • per ogni service viene generata una interfaccia serviz ed un service locator Inoltre, specificando alcuni parametri si possono generare anche i file lato server, in particolare con java org.apache.axis.WSDL.WSDL2Java -s -S true descr.WSDL Vengono generati • per ogni binding un template della classe che implementa il servizio • per tutti i servizi i file per il deploy e l’undeploy 2.10 Generazione di un servizio web La creazione di un servizio web può essere facilmente realizzata utilizzando i tool Java2WSDL e WSDL2Java. Descriveremo in questa sezione gli step necessari per costruire un servizio web partendo da una interfaccia Java (tali step forniscono solo un indicazione, non sono l’unico modo per avere un implementazione di un web service con Axis). 2.10.1 Creazione dell’interfaccia Il primo step è la creazione dell’interfaccia Java che descrive l’interfaccia del servizio, ad esempio: Listing 2.15: Interfaccia Java 1 package net.nepero.portal159.passwordcollector; 2 3 4 5 6 7 /** * La classe PasswordCollector realizza il sistema per la memorizzazione * della password in un db del tipo DbText (e’ un file di testo) * * @author Giacomo Sacchetti <[email protected]> 2.10. GENERAZIONE DI UN SERVIZIO WEB 8 9 39 * @version 2-Ott-2006 */ 10 11 12 13 import java.io.IOException; import net.nepero.db.text.DbText; import net.nepero.util.AssociativeArray; 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public class PasswordCollector { /** * cancellazione informazioni su un servizio * username * @param sUsername nome del servizio * @param sService */ public void deleteAuthForService(String sUsername, String sService) throws NoSuchFieldException, IOException { [...] } 28 29 30 31 32 33 34 35 36 37 38 39 40 /** * inserimento informazioni su un servizio * informazione di autenticazione * @param info / * public void insertAuthForService(AuthInfo info) throws IOException, DuplicateIdentifierException, NoSuchFieldException { [...] } 41 42 43 44 45 46 47 48 49 50 51 52 53 54 /** * recupero informazioni su un servizio * username * @param sUsername @param sService nome del servizio * @return informazioni di autenticazione sul servizio * / * public AuthInfo getAuthForService(String sUsername, String sService) throws NoSuchFieldException, IOException { [...] } 55 56 /** CAPITOLO 2. AXIS 40 * recupero informazioni su un servizio * username * @param sUsername * @return vettore di info di autenticazione di un utente */ public AuthInfo[] getAuthForUser (String sUsername) throws BackingStoreException, IOException, NoSuchFieldException { [...] } 57 58 59 60 61 62 63 64 65 66 67 68 69 } 2.10.2 Creazione del WSDL Il secondo step è l’utilizzo del tool Java2WSDL per creare il file WSDL partendo dall’interfaccia del servizio. Ad esempio, tramite l’invocazione di java org.apache.axis.wsdl.Java2WSDL -o passwordcollector.wsdl -l"http://localhost:8080/axis/services/PasswordCollector" -n"urn:PasswordCollector" -p"net.nepero.portal159.passwordcollector" "urn:PasswordCollector" net.nepero.portal159.passwordcollector.PasswordCollector dove abbiamo che • l’opzione “-o” serve per specificare il nome del file WSDL di output • l’opzione “-l” serve per specificare la locazione del servizio • l’opzione “-n” è il target namespace del file WSDL • l’opzione “-p” serve per specificare il mapping dal package al namespace • infine la classe specificata è l’interfaccia del servizio Se l’interfaccia che abbiamo definito ci sono riferimenti a classi definite dall’utente, come nell’esempio precedente, il tool Java2WSDL si occuperà di convertire tali tipi alla rappresentazione in XML oppurtuna, cosı̀ come descritto nei paragrafi precedenti. 2.10.3 Creazione dei bindings con WDSL2Java Il terzo step consiste nell’usare il file WDSL appena generato per costruire il binding client/server appropriato per il web service. Per far ciò si usa il tool WDSL2Java: 2.10. GENERAZIONE DI UN SERVIZIO WEB 41 java org.apache.axis.wsdl.WSDL2Java -o . -d Session -s -S true -Nurn:PasswordCollector net.nepero.portal159.passwordcollector passwordcollector.wsdl In questo caso verranno generati i seguenti file: • PasswordCollectorSoapBindingImpl.java è il file che contiene l’implementazione lato server del web service • PasswordCollector.java la nuova interfaccia del servizio, che contiene le appropriate chiamate a java.rmi.Remote • PasswordCollectorService.java è il file che contiene l’interfaccia lato client del servizio • PasswordCollectorServiceLocator.java è il file contiene l’implementazione dell’interfaccia lato client • PasswordCollectorSoapBindingSkeleton.java lo skeleton lato server • PasswordCollectorSoapBindingStub.java lo stub lato client • deploy.wsdd descrittore per il deploy del servizio • undeploy.wsdd descrittore per l’undeploy del servizio Nella versione di Axis che abbiamo utilizzato, la creazione del file deploy.wsdd non sempre è corretta. Nell’utilizzo di questo tool, non viene infatti creato il mapping corretto per rappresentare i vettori di classi JavaBean definite dall’utente. In particolare il tipo AuthInfo[] viene mappato nel descrittore del servizio come: Listing 2.16: Rappresentazione errata di un array 1 2 3 4 5 6 7 8 <arrayMapping xmlns:ns="urn:PasswordCollector" qname="ns:ArrayOf_soapenc_string" type="java:java.lang.String[]" innerType="cmp-ns:string" xmlns:cmp-ns="http://schemas.xmlsoap.org/soap/encoding/" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> Con tale rappresentazione non è possibile deserializzare il tipo da parte del client. La rappresentazione corretta è invece: CAPITOLO 2. AXIS 42 Listing 2.17: Rappresentazione corretta di un array 1 2 3 4 5 6 7 8 <typeMapping xmlns:ns="urn:PasswordCollector" qname="ns:ArrayOfAuthInfo" type="java:net.nepero.portal159.passwordcollector.AuthInfo[]" serializer="org.apache.axis.encoding.ser.ArraySerializerFactory" deserializer="org.apache.axis.encoding.ser.ArrayDeserializerFactory" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> 2.11 Il servizio PasswordCollector Il servizio PasswordCollector nasce con l’intento di realizzare una base di dati centralizzata per memorizzare le informazioni di accesso a vari servizi web. In particolare PasswordCollector memorizza le informazioni relative all’autenticazione BASIC dei web services, è anch’esso un web service che usa l’autenticazione di tipo BASIC per l’accesso. Lo schema UML che mostra l’interazione tra agenti per l’utilizzo del servizio è mostrata nella figura 2.6. In pratica, avendo accesso al servizio PasswordCollector è possibile reperire da una base di dati le informazioni di accesso per altri servizi, inserire nuove informazioni ed eventualmente cancellarle. L’interfaccia del servizio è già stata presentato nel paragrafo precedente ed il suo codice è mostrato nel listato 2.15. Notiamo in questo codice che esiste un metodo, getAuthForService, il cui tipo di ritorno è AuthInfo: è un tipo che abbiamo noi stesso definito allo scopo di mostrare il mapping che i tool di Axis riescono ad effettuare. La definizione di questo tipo è mostrata nel listato 2.18. Listing 2.18: Il tipo AuthInfo 1 2 3 4 5 6 7 8 9 10 11 12 13 14 package net.nepero.portal159.passwordcollector; /** * Write a description of class AuthInfo here. * * @author Giacomo Sacchetti <[email protected]> * @version 2-Ott-2006 */ public class AuthInfo { private String sServiceCall; private String sServiceName; private String sServicePassword; private String sServiceUsername; private String sUsername; 2.11. IL SERVIZIO PASSWORDCOLLECTOR Figura 2.6: Interazione con il servizio PasswordCollector 43 44 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 CAPITOLO 2. AXIS /** * Constructor for objects of class AuthInfo */ public AuthInfo() { sServiceCall = new String(""); sServiceName = new String(""); sServicePassword = new String(""); sServiceUsername = new String(""); sUsername = new String(""); } // metodi get/set public void setUsername(String username) { sUsername = username; } public String getUsername() { return sUsername; } public void setServiceCall(String servicecall) { sServiceCall = servicecall; } public String getServiceCall() { return sServiceCall; } public void setServiceName(String servicename) { sServiceName = servicename; } public String getServiceName() { return sServiceName; } public void setServicePassword(String servicepassword) { sServicePassword = servicepassword; } public String getServicePassword() { return sServicePassword; } public void setServiceUsername(String serviceuser) { sServiceUsername = serviceuser; } public String getServiceUsername() 2.11. IL SERVIZIO PASSWORDCOLLECTOR { 64 return sServiceUsername; 65 } 66 67 45 } Seguendo la metodologia che abbiamo descritto nel paragrafo precendente, l’interfaccia PasswordCollector è stata processata dal tool Java2WSDL, ed il risultato è il seguente file WSDL: Listing 2.19: passwordcollector.wsdl 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 <?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions targetNamespace="urn:PasswordCollector" xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:impl="urn:PasswordCollector" xmlns:intf="urn:PasswordCollector" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <!--WSDL created by Apache Axis version: 1.4 Built on Apr 22, 2006 (06:55:48 PDT)--> <wsdl:types> <schema targetNamespace="urn:PasswordCollector" xmlns="http://www.w3.org/2001/XMLSchema"> <import namespace="http://schemas.xmlsoap.org/soap/encoding/"/> <complexType name="AuthInfo"> <sequence> <element name="serviceCall" nillable="true" type="soapenc:string"/> <element name="serviceName" nillable="true" type="soapenc:string"/> <element name="servicePassword" nillable="true" type="soapenc:string"/> <element name="serviceUsername" nillable="true" type="soapenc:string"/> <element name="username" nillable="true" type="soapenc:string"/> </sequence> </complexType> <complexType name="DuplicateIdentifierException"> <sequence/> </complexType> <complexType name="ArrayOfAuthInfo"> <complexContent> <restriction base="soapenc:Array"> <attribute ref="soapenc:arrayType" wsdl:arrayType="impl:AuthInfo[]"/> </restriction> </complexContent> </complexType> </schema> </wsdl:types> 46 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 CAPITOLO 2. AXIS <wsdl:message name="DuplicateIdentifierException"> <wsdl:part name="fault" type="impl:DuplicateIdentifierException"/> </wsdl:message> <wsdl:message name="deleteAuthForServiceRequest"> <wsdl:part name="sUsername" type="soapenc:string"/> <wsdl:part name="sService" type="soapenc:string"/> </wsdl:message> <wsdl:message name="insertAuthForServiceRequest"> <wsdl:part name="info" type="impl:AuthInfo"/> </wsdl:message> <wsdl:message name="getAuthForUserResponse"> <wsdl:part name="getAuthForUserReturn" type="impl:ArrayOfAuthInfo"/> </wsdl:message> <wsdl:message name="insertAuthForServiceResponse"> </wsdl:message> <wsdl:message name="deleteAuthForServiceResponse"> </wsdl:message> <wsdl:message name="getAuthForUserRequest"> <wsdl:part name="sUsername" type="soapenc:string"/> </wsdl:message> <wsdl:message name="getAuthForServiceResponse"> <wsdl:part name="getAuthForServiceReturn" type="impl:AuthInfo"/> </wsdl:message> <wsdl:message name="getAuthForServiceRequest"> <wsdl:part name="sUsername" type="soapenc:string"/> <wsdl:part name="sService" type="soapenc:string"/> </wsdl:message> <wsdl:portType name="PasswordCollector"> <wsdl:operation name="deleteAuthForService" parameterOrder="sUsername sService"> <wsdl:input message="impl:deleteAuthForServiceRequest" name="deleteAuthForServiceRequest"/> <wsdl:output message="impl:deleteAuthForServiceResponse" name="deleteAuthForServiceResponse"/> </wsdl:operation> <wsdl:operation name="insertAuthForService" parameterOrder="info"> <wsdl:input message="impl:insertAuthForServiceRequest" name="insertAuthForServiceRequest"/> <wsdl:output message="impl:insertAuthForServiceResponse" name="insertAuthForServiceResponse"/> <wsdl:fault message="impl:DuplicateIdentifierException" name="DuplicateIdentifierException"/> </wsdl:operation> <wsdl:operation name="getAuthForService" parameterOrder="sUsername sService"> <wsdl:input message="impl:getAuthForServiceRequest" name="getAuthForServiceRequest"/> <wsdl:output message="impl:getAuthForServiceResponse" 2.11. IL SERVIZIO PASSWORDCOLLECTOR 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 47 name="getAuthForServiceResponse"/> </wsdl:operation> <wsdl:operation name="getAuthForUser" parameterOrder="sUsername"> <wsdl:input message="impl:getAuthForUserRequest" name="getAuthForUserRequest"/> <wsdl:output message="impl:getAuthForUserResponse" name="getAuthForUserResponse"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="PasswordCollectorSoapBinding" type="impl:PasswordCollector"> <wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="deleteAuthForService"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="deleteAuthForServiceRequest"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:PasswordCollector" use="encoded"/> </wsdl:input> <wsdl:output name="deleteAuthForServiceResponse"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:PasswordCollector" use="encoded"/> </wsdl:output> </wsdl:operation> <wsdl:operation name="insertAuthForService"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="insertAuthForServiceRequest"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:PasswordCollector" use="encoded"/> </wsdl:input> <wsdl:output name="insertAuthForServiceResponse"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:PasswordCollector" use="encoded"/> </wsdl:output> <wsdl:fault name="DuplicateIdentifierException"> <wsdlsoap:fault encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" name="DuplicateIdentifierException" namespace="urn:PasswordCollector" use="encoded"/> </wsdl:fault> </wsdl:operation> <wsdl:operation name="getAuthForService"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="getAuthForServiceRequest"> CAPITOLO 2. AXIS 48 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:PasswordCollector" use="encoded"/> </wsdl:input> <wsdl:output name="getAuthForServiceResponse"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:PasswordCollector" use="encoded"/> </wsdl:output> </wsdl:operation> <wsdl:operation name="getAuthForUser"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="getAuthForUserRequest"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:PasswordCollector" use="encoded"/> </wsdl:input> <wsdl:output name="getAuthForUserResponse"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:PasswordCollector" use="encoded"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="PasswordCollectorService"> <wsdl:port binding="impl:PasswordCollectorSoapBinding" name="PasswordCollector"> <wsdlsoap:address location="http://localhost:8080/axis/services/PasswordCollector"/> </wsdl:port> </wsdl:service> </wsdl:definitions> Adesso tale file và processato attraverso il tool WSDL2Java, che genererà i file sorgente Java necessari per realizzare client e server, ed i descrittori del servizio, in particolare: • per il web service i file sono: – PasswordCollector.java – PasswordCollectorSoapBindingImpl.java – PasswordCollectorSoapBindingSkeleton.java • per il client: – PasswordCollectorService.java 2.11. IL SERVIZIO PASSWORDCOLLECTOR 49 – PasswordCollectorSoapBindingStub.java – PasswordCollectorServiceLocator.java • per la pubblicazione: deploy.wsdd, undeploy.wsdd (vanno modificati secondo quanto detto nel paragrafo precedente) Solitamente l’unico file che và modificato, per inserire l’implementazione del servizio, è PasswordCollectorSoapBindingImpl.java, ma nella nostra applicazione è necessario compiere alcune modifiche lato client per gestire l’autenticazione. Apportate le opportune modifiche è necessario copiare i file PasswordCollector.class PasswordCollectorSoapBindingImpl.class PasswordCollectorSoapBinsingSkeleton.class in CATALINA BASE/webapps/axis/WEB-INF/classes (con le opportune directory date dal package a cui tali classi appartengono). Infine è necessario eseguire il deploy del servizio, tramite l’applicazione AdminClient: neperobook: giacomo$ java org.apache.axis.client.AdminClient \ net/nepero/portal159/passwordcollector/deploy.wsdd Processing file net/nepero/portal159/passwordcollector/deploy.wsdd <Admin>Done processing</Admin> Se il deploy del servizio ha avuto successo, esso sarà visibile all’indirizzo http://localhost:8080/axis/servlet/AxisServlet come è mostrato nella figura 2.7. A questo punto il servizio è pronto per essere utilizzato, ed abbiamo per questo realizzato una piccola applicazione web per la gestione delle informazioni di autenticazione. Tale applicazione web è scritta in JSP ed all’interno del codice vengono effettuate le chiamate al servizio PasswordCollector proprio attraverso le classi stub generate dal tool WSDL2Java. Alcune pagine dell’applicazione web sono mostrate nelle figure seguenti. CAPITOLO 2. AXIS 50 Figura 2.7: Servizio PasswordCollector pubblicato Figura 2.8: Login 2.11. IL SERVIZIO PASSWORDCOLLECTOR Figura 2.9: Gestione servizi Figura 2.10: Aggiunta di un servizio 51 52 CAPITOLO 2. AXIS Il Semantic Web è un’estensione dell’attuale Web, nella quale all’informazione viene dato un significato ben definito, permettendo cosı̀ ai computer e alle persone di lavorare meglio in cooperazione. Tim Berners-Lee, James Hendler, Ora Lassila, The Semantic Web, Scientific American A Web Semantico A.1 Il Web attuale Come è ben precisato nella citazione iniziale di questo capitolo, il Semantic Web o Web Semantico, non è una realtà alternativa rispetto al Web attuale, ma piuttosto un’estensione che dovrebbe potenziarne le funzionalità. Tale estensione costituisce una soluzione ai principali limiti dell’attuale Web: Ricerca di documenti Per trovare documenti nell’attuale Web, esistono fondamentalmente due strade: seguire i link da una pagina all’altra, fino a raggiungere l’informazione che ci interessa, oppure servirci di un motore di ricerca per ottenere una lista di link tra i quali selezionare quello che ci interessa. La prima soluzione è una processo cognitivamente ricco per un essere umano, perchè in genere riusciamo a capire il contenuto della pagina a cui punta il link in base alla descrizione che ne troviamo, o da altre informazioni relative al contesto a cui appartiene. Tuttavia questo metodo può essere dispendioso in termini di tempo e difficile da avviare se non sappiamo da dove partire. Utilizzare invece i motori di ricerca ha il vantaggio di richiedere poche informazioni di partenza, ma essi non coprono tutto il contenuto Web (è stimato che circa l’80% del Web è nascosto) e può essere frustrante perchè nella lista compaiono spesso dei falsi-positivi () o falsi-negativi (). 53 54 APPENDICE A. WEB SEMANTICO Ricerca di informazione Un altro limite del Web è che la ricerca restituisce sempre documenti, quindi non precisamente l’informazione che cercavamo. Integrazione di informazione Spesso diverse parti delle informazioni cercate sono contenute in documenti diversi, magari su siti diversi: non sono però esprimibili i concetti per correlare queste parti. Cooperazione Il Web attuale non consente la cooperazione tra programmi e tra programmi e essere umani per risolvere problemi più complessi. I siti Web sono progettati come contenitori di informazioni e non come fornitori di servizi. A.2 Il progetto Semantic Web Il Sematic Web è un progetto di ricerca che ha lo scopo di ridefinire e ristrutturare i dati su Web in modo che il loro significato sia accessibile non solo ad utenti umani, ma anche a programmi che li utilizzano per manipolarli, integrarli, renderli disponibili ad altri programmi (attualmente le informazioni vengono solamente mostrate). Tale risultato si basa sui seguenti concetti: Rappresentazione della conoscenza Per poter fornire un risultato soddisfacente per l’utente, i programmi scritti per il Semantic Web devono avere un accesso al significato dei dati con cui lavorano. Per far ciò è necessario raccogliere tali dati, strutturarli e corredarli di metadati (dati che descrivono dati). Utilizzo delle ontologie I soli linguaggi non dispongono di uno strato concettuale che leghi i termini tra loro, mostrandone le relazioni, in modo da farne emergere il significato. Questo compito è svolto dalle ontologie, documenti che hanno lo scopo di esprimere il significato, inteso come un certo insieme di termini, definendone le relazioni reciproche. Le ontologie pensate per il Web hanno spesso la forma di tassonomie corredate di un insieme di regole di inferenza e forniscono definizioni formali delle relazioni. Agenti software Gli agenti software sono programmi che dovrebbero sfruttare la conoscenza contenuta nei metadati per fornire servizi complessi agli utenti del Semantic Web. Gli agenti sono entità abbastanza autonome e sono capaci di ragionare in modo complesso sull’informazione a cui hanno accesso: devono essere in grado di rappresentare gli obiettivi di un certo utente, di mettere in atto una sequenza di azioni che possa soddisfare tali A.2. IL PROGETTO SEMANTIC WEB 55 obiettivi ed eventualmente di cooperare con altri agenti per ottenere tale risultato. Uso degli standard Ovviamente per poter realizzare metadati e conoscenza è necessario utilizzare dei formati standard, basati su XML, per poter definire tali caratteristiche. 56 APPENDICE A. WEB SEMANTICO Bibliografia [Web Arch] Ian Jacobs, Norman Walsh, Architecture of the World Wide Web, W3C Reccomendation, 15th December 2004 [IBM SOA] Steve Burbeck, The Tao of e-business services, IBM DeveloperWorks, 1st October 2000 [Hao He] Hao He, What is Service-Oriented Architecture?, O’Reilly webservices.xml.com, 30th September 2003 [WSA] David Booth, Hugo Haas, Francis McCabe, Eric Newcomer, Michael Champion, Chris Ferris, David Orchard Web Services Architecture,W3C Working Group Note, 11th February 2004 [Axis User’ s Guide] Apache Software Foundation, Axis User’s Guide, 1.2 Version, 2005 [Tecno] Ludwig Bargagli, Gabriele Fatigati, Implementazione e protezione di Web Services con Oc4j ed Axis, http://www.tecnoteca.it/howto/oc4j 57