MokaByte 62 - Aprile 2002 
Web Services
VII parte: semplificare applicazioni distribuite SOAP con JAX-RPC
di
Massimiliano Bigatti
Come abbiamo visto ([1]), JAXM consente di definire in modo programmatico messaggi SOAP e di inviarli tramite HTTP secondo un paradigma di fire&forget (anche detto Oneway) o di request/response. Come noto, le specifiche SOAP 1.1 contengono al loro interno indicazioni di come é possibile utilizzare messaggi che utilizzino questo formato, non solo per la trasmissione di informazioni, ma pił organicamente come mezzo per implementare sistemi distribuiti basati su XML.

Introduzione
Come abbiamo visto ([1]), JAXM consente di definire in modo programmatico messaggi SOAP e di inviarli tramite HTTP secondo un paradigma di fire&forget (anche detto Oneway) o di request/response. Come noto, le specifiche SOAP 1.1 contengono al loro interno indicazioni di come é possibile utilizzare messaggi che utilizzino questo formato, non solo per la trasmissione di informazioni, ma più organicamente come mezzo per implementare sistemi distribuiti basati su XML.

 

A basso livello
Per sistema distribuito basato su messaggi XML si può immaginare qualche cosa di simile ad una applicazione basata su RMI, ma che utilizzi XML come protocollo di filo. In applicazioni RMI, un server espone dei servizi, mostrati come metodi di oggetti remoti, ed il client utilizza questi servizi chiamando le interfacce remote. Questo avviene in modo trasparente rispetto allo sviluppatore.
L'inizio del processo avviene sul lato client, ma l'elaborazione avviene sul server: questo é il concetto fondamentale delle applicazioni distribuite (ove ci siano più server, o del paradigma client/server se i livelli sono solo due). Come noto RMI si basa su JRMP per implementare il protocollo di filo e cioé per definire tutte quelle meta-informazioni necessarie a far si che la comunicazione bidirezionale avvenga con successo (anche se é disponibile anche il protocollo IIOP - quello nativo CORBA).
Nel mondo dei Web Services, SOAP é il "protocollo di filo" più diffuso delle applicazioni distribuite (ne esistono altri, come XML-RPC) e SOAP RPC é quella parte di specifiche SOAP che definisce le semantiche di comunicazione.
JAXM é un po' l'API "a basso livello" per il protocollo SOAP, rappresenta dunque l'implementazione del protocollo di filo.
Come tutte le API a basso livello, richiede più lavoro per ottenere le cose. Come si é visto nell'articolo del mese precedente (e come si vedrà nelle successive puntate della serie dedicata allo sviluppo di una chat basata su SOAP la cui prima parte é pubblicata in questo stesso numero), é necessario specificare tramite opportune chiamate a metodi, ciascun elemento del messaggio SOAP, dai tag Envelope, Header e Body, ai namespace, all'encoding ed anche alle intestazioni HTTP come SOAPAction.
La buona notizia é che come RMI semplifica notevolmente il lavoro nello sviluppo di applicazioni distribuite tradizionali, nel mondo dei Web Services Java, lo stesso ruolo lo ricopre JAX-RPC.
A prima vista si sarebbe potuto pensare che JAXM e JAX-RPC si sovrapponessero, in quanto SOAP, che sta alla base di entrambe, definisce sia standard di messaggio che protocolli di RPC.
La differenza é che JAXM consente semplicemente di creare, consumare ed inviare messaggi SOAP mentre JAX-RPC si occupa degli aspetti ad alto livello e cioé di mappare interfacce e servizi Java come servizi Web. JAX-RPC é dunque qualche cosa di più vasto, che si può appoggiare a JAXM per l'implementazione di SOAP (in realtà la Early Access 1 di JAX-RPC utilizza Apache SOAP, anche se é facile aspettarsi che in futuro l'implementazione venga allineata all'uso di JAXM), ma che si occupa degli aspetti più complessi legati a problematiche di RPC. Inoltre queste API non sono legate solamente a SOAP ma potrebbero utilizzare protocolli XML di filo diversi da questo.

 

Basta un file WSDL...
La caratteristica interessante di JAX-RPC é che può utilizzare, come file di definizione del servizio, un documento WSDL (Web Services Definition Language - si veda [2] e [3]). Un file di definizione WSDL contiene tutte le informazioni necessarie per definire gli input, gli output e la destinazione fisica del servizio. Tutte queste informazioni sono sufficienti per eseguire una mappatura WSDL/Java, che viene eseguita da codice generato dal tool xrpcc.
(Un esempio di file WSDL é presente nel listato 1).

Listato 1. Un esempio di WSDL
<?xml version="1.0"?>
<definitions name="StockQuote"

targetNamespace="http://example.com/stockquote.wsdl"
xmlns:tns="http://example.com/stockquote.wsdl"
xmlns:xsd1="http://example.com/stockquote.xsd"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns="http://schemas.xmlsoap.org/wsdl/">

<types>
<schema targetNamespace="http://example.com/stockquote.xsd"
xmlns="http://www.w3.org/2000/10/XMLSchema">
<element name="TradePriceRequest">
<complexType>
<all>
<element name="tickerSymbol" type="string"/>
</all>
</complexType>
</element>
<element name="TradePrice">
<complexType>
<all>
<element name="price" type="float"/>
</all>
</complexType>
</element>
</schema>
</types>

<message name="GetLastTradePriceInput">
<part name="body" element="xsd1:TradePriceRequest"/>
</message>

<message name="GetLastTradePriceOutput">
<part name="body" element="xsd1:TradePrice"/>
</message>

<portType name="StockQuotePortType">
<operation name="GetLastTradePrice">
<input message="tns:GetLastTradePriceInput"/>
<output message="tns:GetLastTradePriceOutput"/>
</operation>
</portType>

<binding name="StockQuoteSoapBinding" type="tns:StockQuotePortType">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="GetLastTradePrice">
<soap:operation soapAction="http://example.com/GetLastTradePrice"/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
</binding>

<service name="StockQuoteService">
<documentation>My first service</documentation>
<port name="StockQuotePort" binding="tns:StockQuoteBinding">
<soap:address location="http://example.com/stockquote"/>
</port>
</service>

</definitions>

Questo file, dato come input al tool xrpcc di JAX-RPC (non fa parte delle specifiche, ma solo della reference implementation), produce gli stub e dei ties (simili a skeleton RMI) per l'implementazione della comunicazione SOAP client/server. Il tool xrpcc ci porta alla memoria quella che potrebbe essere considerata la sua controparte nella tecnologia RMI: rmic.
L'architettura che si ottiene é esemplificata in Figura 1.



Figura 1 - architettura client/server JAX-RPC

Il codice sorgente prodotto (pure Java) utilizza il runtime JAX-RPC e fornisce una rappresentazione tramite interfacce Java del servizio web. Il tool xrpcc si occupa inoltre di compilare i sorgenti: i binari server prodotti potranno poi essere inseriti in un container JAX-RPC (nel JWSDP ea2 é Tomcat con la RI di JAX-RPC) insieme ad un file di proprietà che definsce alcuni parametri di funzionamento.
I binari client potranno essere invece utilizzati sul lato client per interfacciare il servizio web come se fosse una classe Java.
Lo strumento xrpcc può generare solo gli stub, solo i ties o entrambe le cose, in funzione del fatto che si stia sviluppando un client per un servizio web, oppure la sua implementazione, oppure tutti e due.

 

Generare il codice
Il file WSDL deve essere fornito ad xrpcc tramite un altro file XML intermedio che indica informazioni aggiuntive necessarie alla generazione del codice, quale il package di destinazione. Un esempio é presente nel Listato 2.

Listato 2. Esempio file configurazione xrpcc (1)
<?xml version="1.0" encoding="UTF-8"?>
<configuration
xmlns="http://java.sun.com/jax-rpc-ri/xrpcc-config">
<wsdl name="StockQuoteModel"
location="file:sq.wsdl.xml"
packageName="stockQuote">
</wsdl>
</configuration>

Per generare il codice é sufficiente invocare il comando xrpcc:

xrpcc -both -keep file.xml

Le opzioni hanno questo significato: both indica di generare sia gli stub che i tie, mentre keep indica di non cancellare i file sorgenti dopo la compilazione, questo é utile per "curiosare" nei sorgenti generati da xrpcc. L'ultimo parametro del comando é il nome del file di lancio (quello presente nel listato 2).
L'esempio WSDL presente nel listato 1 é tratto dalle specifiche WSDL.

Nota: sono specifiche prodotte da SUN ed IBM e sottomesse come "nota" al W3C. NON sono dunque uno standard W3C ma semplicemente informazioni a lei inviate e che questo ente ritiene "interessanti" (le ha riconosciute come "nota"). Tutto questo materiale (insieme a SOAP 1.2, XML Protocol e tutte le attività connesse) rientreranno nel gruppo di lavoro che W3C ha organizzato per definire i suoi standard per i Web Services. Una volta prodotte le specifiche finali, queste potranno essere realmente considerate "standard", alla stregua di HTML ed HTTP, ma non prima.

La brutta notizia é che, anche nell'ultima versione disponibile "Java Web Services Development Pack" JWSDP Early Access 2, questo file non é interpretabile da xrpcc. La cosa é alquanto strana, visto che la conformità ad uno standard dovrebbe partire dalla compatibilità almeno con gli esempi presenti nello standard stesso. Due possibili spiegazioni: la prima é che la reference implementation (RI) é in early access, e dunque soggetta a migliorie prima di arrivare alla versione definitiva. La seconda: sono tecnologie molto nuove: potrei aver sbagliato qualche cosa! In questo caso invito i lettori a segnalarmelo: il primo che mi indicherà l'errore, verrà citato con onore nel prossimo numero di questa "rubrica".
Ho avuto più fortuna con altri file WSDL: il servizio Babelfish di Altavista o il servizio per la lettura delle vignette di Dilbert (http://www.dilbert.com) non hanno riscontrato problemi (anche se poi dovrà essere verificata l'effettiva funzionalità di quanto generato). Per un interessante elenco di servizi web, é possibile fare riferimento al sito web www.methods.net.

 

Da Java ai Web Services
Abbiamo visto come, partendo da un file di definizione di un servizio web in formato WSDL, sia possibile generare sia un client Java per il servizio, sia un framework per l'implementazione del servizio lato server.
E' possibile anche l'operazione inversa: da una interfaccia Java é possibile generare stubs, ties ed anche il file WSDL. In questo modo diventa estremamente semplice esporre un web service sviluppato in Java, fornendo all'esterno il file WSDL.
Le possibilità offerte da JAX-RPC sono descritte in figura 2


Figura 2
- generazione del codice in JAX-RPC

Anche in questo caso lo strumento é sempre xrpcc, mentre il file di definizione é diverso e contiene piuttosto i riferimenti alle interfacce Java da utilizzare. Un esempio di questo file é presente nel listato 3.

Listato 3. Esempio configurazione xrpcc (2)

<?xml version="1.0" encoding="UTF-8"?>
<configuration
xmlns="http://java.sun.com/jax-rpc-ri/xrpcc-config">
<rmi name="StockQuoteService"
targetNamespace="http://schemas.mokabyte.it/wsdl"
typeNamespace="http://schemas.mokabyte.it/types">
<service name="StockQuoteService" packageName="stockquote">
<interface name="StockQuoteProvider"
servantName="StockQuoteImpl"/>
</service>
</rmi>
</configuration>

Il servizio StockQuoteService a cui si riferisce il file di configurazione di xrpcc é molto semplice. L'interfaccia é costituita da un singolo metodo che fornisce la quotazione dell'azione in formato float. Il nome dell'azione é un dato di tipo String passato come parametro.
In JAX-RPC le interfacce devono estendere java.rmi.Remote, in modo che il compilatore xrpcc possa riconoscerle. Ciascun metodo dovrà lanciare una eccezione java.rmi.RemoteException.
Anche per quanto riguarda le interfacce per i Web Services JAX-RPC si riscontra una certa congruenza con RMI, cosa senz'altro positiva.
Nonostante questo, non si può però pensare di prendere interfacce RMI esistenti e passarle attraverso JAX-RPC per abilitare ai Web Services una applicazione RMI esistente, questo perché JAX-RPC ha limitazioni, sia intrinseche, ma soprattutto legate a SOAP, che non consentono di implementare tutte le funzionalità di una classica applicazione distribuita RMI. In particolare non é disponibile la garbage collection distribuita e la gestione degli stati persistenti.

 

Conclusioni
L'insieme delle specifiche che formano JAX-RPC forniscono una mappatura a due vie: da WSDL a Java e da Java a WSDL. Questo consente allo sviluppatore di trattare un servizio web come se questo fosse una classe Java "tipo" RMI. Inoltre, consente con la stessa semplicità, di esporre classi Java come servizi Web.
L'incremento di produttività dato da questi automatismi, se confrontato al lavoro richiesto per implementare le stesse funzionalità con JAXM, é notevole.
D'altro canto, come per tutti i meccanismi che forniscono automatismi, una piccola modifica a livello di interfaccia può comportare anche una grande variazione ai livelli più bassi. Per questo motivo é necessario porre attenzione all'uso che si fa degli strumenti non sottovalutando le tecnologie sottostanti che, anche se nascoste, rappresentano un cuore importante da non dimenticare.

 

Bibliografia
[1] Massimiliano Bigatti - "Web Services (6) - Java API for XML Messaging (JAXM)", Mokabyte, Marzo 2002
[2] Specifiche WSDL - http:/www.w3c.org/TR/wsdl
[3] Massimiliano Bigatti – "Web services (2): capire i WSDL", Mokabyte, Giugno 2001


Massimiliano Bigatti è SUN Certified Enterprise Architect for Java Platform, Enterprise Edition Technology. Si occupa di architetture applicative basate su Java ed Internet, technical writing e musica rock

MokaByte® è un marchio registrato da MokaByte s.r.l. 
Java®, Jini® e tutti i nomi derivati sono marchi registrati da Sun Microsystems.
Tutti i diritti riservati. E' vietata la riproduzione anche parziale.
Per comunicazioni inviare una mail a info@mokabyte.it