Spring permette di “esporre” i propri servizi sotto forma di web services basati sullo standard JAX-RPC e anche di accedere a generici web services in maniera trasparente dal punto di vista del codice client. Si tratterà come sempre di gestire la configurazione di Spring, in modo che quest‘ultimo “lavori” per noi dietro le quinte per consentirci un accesso ai servizi remoti alla stregua dei componenti locali.
Introduzione
Integrare delle funzionalità esterne all‘ambito “locale” della propria applicazione è una necessità molto comune oggigiorno. L‘ambiente in cui particolari servizi vivono può essere più o meno esteso. Può essere circoscritto a una singola applicazione, nel caso di Java una singola Java Virtual Machine, a una rete locale, a una rete geografica o nella prospettiva più larga a Internet. Le tecnologie utilizzate per “distribuire” dei servizi in uno di questi ambiti sono le più varie. Il fattore comune aÃÂ queste tecnologie è quello di utilizzare un insieme di regole atto all‘esecuzione di procedure remote, che si può sintetizzare nella sigla RPC (Remote Procedure Call). Java fornisce un suo protocollo per l‘RPC, denominato RMI (Remote Method Invocation), che costituisce tra l‘altroÃÂ la base per la tecnologia EJB (Enterprise Java Beans). L‘uso di RMI e della tecnologia EJB ha senso generalmente per reti locali, e normalmente lo scenario è quello di distribuire i componenti applicativi in un nodo specifico accessibile dai componenti di frontend. Rendere i propri servizi accessibili in Internet implica invece utilizzare come canale di comunicazione il protocollo HTTP, dato che esso permette di attraversare le protezioni firewall delle varie reti, presupposto per avere delle funzionalità integrabili con degli standard globali e perfettamente “delocalizzate”.
Esistono alcune soluzioni che implementano l‘RPC utilizzando l‘HTTP, come per esempio l‘Hessian, ma lo standard accettato universalmente oramai è il protocollo SOAP, basato su XML. I servizi basati su SOAP sono chiamati web services e nel mondo Java la tecnologia che implementa l‘RPC basato su SOAP è la JAX-RPC. Spring fornisce un suo supporto per esporre e per integrare web services che dietro le quinte utilizza appunto lo standard JAX-RPC. Nel prossimo paragrafo verrà spiegato come esporre delle funzionalità sotto forma di web services, mentre nel successivo come accedere nella propria applicazione basata su Spring a dei generici web services “pubblicati” in un qualche nodo su Internet.
Distribuire dei servizi
Immaginiamo di avere la seguenteÃÂ interfaccia:
public interface MyService {
ÃÂ public void doSomething();
}
e la sua corrispettiva remota, che estende l‘interfaccia Remote di RMI
public interface RemoteMyService extends Remote {
ÃÂ public void doSomething() throws RemoteException ;
}
Quest‘ultima è necessaria perché Spring utilizza JAX-RPC per supportare i web services, e quest‘ultima tecnologia è basata sul protocollo RMI. Per esporre questa interfaccia come servizio web dobbiamo utilizzare un‘estensione della classe ServletEndpointSupport che implementi l‘interfaccia remota RemoteMyService. L‘implementazione effettiva è delegata al bean myService che implementa invece l‘interfaccia “locale”, configurato nell‘ApplicationContext di Spring.
public class MyServiceEndpoint extends ServletEndpointSupport implements RemoteMyService {
ÃÂ private MyService myServ;
ÃÂ
ÃÂ protected void onInit() {
ÃÂ ÃÂ this. myServ = (MyService) getWebApplicationContext().getBean("myService");
ÃÂ }
ÃÂ
ÃÂ public void doSomething() throws RemoteException {
ÃÂ ÃÂ myServ.doSomething();
ÃÂ }
}
Perchè l‘ApplicationContext sia disponibile la classe deve essere distribuita nella stessa web application sulla quale è in esecuzione Spring. Se si utilizza Axis, occorrerà configurare la servlet AxisServlet nel web.xml e la classe MyServiceEndpoint nel file server-config.wsdd.
Accedere ai servizi
La classe JaxRpcPortProxyFactoryBean permette di ottenere, attraverso le consuete funzionalità AOP, un proxy associato al servizio web al quale si vuole accedere. Ecco il frammento di configurazione necessario a ottenere un proxy del servizio RemoteMyService:
ÃÂ
La proprietà serviceInterface è l‘interfaccia remota del servizio, la wsdlDocumentUrl è il percorso del descrittore del servizio, mentre namespaceUri è l‘URL del servizio. Possiamo a questo punto configurare un componente client al quale “iniettiamo” il riferimento al proxy precedentemente definito:
ÃÂ ...
ÃÂ
Di seguito l‘implementazione del componente client:
public class MyClient {
ÃÂ private RemoteMyService service;
ÃÂ
ÃÂ public void setService(RemoteMyService service) {
ÃÂ ÃÂ this.service = service;
ÃÂ }
ÃÂ
ÃÂ public void foo() {
ÃÂ ÃÂ try {
ÃÂ ÃÂ ÃÂ service.doSomething();
ÃÂ ÃÂ } catch (RemoteException ex) {
ÃÂ ÃÂ ÃÂ ...
ÃÂ ÃÂ }
ÃÂ }
}
Come si vede nell‘implementazione siamo costretti a gestire un‘eccezione di tipo RemoteException. Possiamo evitare questo fornendo in configurazione in aggiunta all‘interfaccia remota la corrispondente interfaccia locale (che non estende la Remote). In questo modo Spring tradurrà la RemoteException nell‘eccezione RemoteAccessException che essendo di tipo “Runtime” non necessita di essere gestita, a meno che non lo si voglia.
ÃÂ
ÃÂesempio.MyService
ÃÂ
ÃÂ
ÃÂesempio.RemoteMyService
ÃÂ
ÃÂ ...
L‘implementazione del client in questo caso diventa:
public class MyClient {
ÃÂ private MyService service;
ÃÂ
ÃÂ public void setService(MyService service) {
ÃÂ ÃÂ this.service = service;
ÃÂ }
ÃÂ
ÃÂ public void foo() {
ÃÂ ÃÂ service.doSomething();
ÃÂ }
}
E in quest‘ultimo caso si vede come sia possibile accedere alle funzionalità del servizio remoto allaÃÂ stregua di un qualsiasi componente locale.
Conclusioni
Si è scelto in questo articolo di esporre l‘integrazione di generici web services in un applicativo Spring. Questo perché i servizi web sono la tecnologia più diffusa e utilizzata per distribuire servizi in Internet. Tuttavia, Spring offre un supporto anche per l‘RMI e per altre tecnologie mirate al generico concetto di Remote Procedure Call, oltre che alla tecnologia EJB. Nel prossimo articolo verrà trattato il caso degli EJB mentre per le altre tecnologie (RMI, Hessian ecc…) si consiglia di consultare la documentazione di riferimento.
Riferimenti
[1] “Spring Reference” 2.0
http://www.springframework.org/
[2] Craig Walls – Ryan Breidenbach, “Spring in Action”, Manning, 2005