SOAP è una delle tecnologie alla base dei Web Service e Apache SOAP era l'implementazione di riferimento per gli sviluppatori Java. Questo articolo presenta Axis , il risultato di un completo ridisegno di Apache SOAP.
Introduzione
I Web Service rappresentano una tecnologia consolidata e si trovano in circolazione diverse implementazioni per eseguire deploy delle proprie applicazioni come web service utilizzando i tre mattoni fondamentali, ovvero SOAP, WSDL e UDDI. Questo articolo è il seguito ideale di [1] e descriverà l'ultima versione dell'implementazione di SOAP per Java fornita dall'Apache Group denominata Axis, Apache eXtendable Interaction System. L'articolo citato mostrava invece Apache SOAP 2.x, la generazione precedente del toolkit.
L'articolo verterà prevalentemente sugli aspetti pratici della realizzazione di un web service con Axis, in particolare si eseguirà il deploy di un EJB con SOAP. Quindi si presenterà un client Java, mostrando come ingegnerizzare il client, e si vedranno varie tecnologie a contorno di Axis sviluppate proprio per semplificare le fasi di invocazione di un web service.
Axis Axis [2] non è un semplice engine SOAP ma un framework per realizzare sistemi di integrazione basati su SOAP. Il progetto non è una revisione della precedente versione del toolkit, Apache SOAP 2.x, ma una completa riscrittura che nasce dalla necessità di disporre di una migliore architettura basata su criteri di flessibilità: è possibile estendere l'engine per eseguire elaborazioni custom degli header dei messaggi; componibilità: i gestori di richieste, chiamati Handler in terminologia Axis, possono essere riutilizzati; indipendenza dal meccanismo di trasporto dei messaggi: in questo modo è possibile utilizzare vari protocolli oltre ad HTTP come SMTP, FTP e messaging.
Rispetto alla versione precedente di SOAP in Axis si è cercato inoltre di migliorare le performance utilizzando SAX per l'elaborazione dei messaggi. Nel seguito si farà riferimeno alla beta 2 di Axis che implementa le specifiche 1.1 di SOAP e offre un supporto parziale a SOAP 1.2.
Installazione
L'installazione di Axis è abbastanza semplice: il prerequisito fondamentale è un servlet container e negli esempi presentati si farà riferimento a Tomcat. Innanzi tutto si deve copiare il folder webapps/axis dalla distribuzione nel folder webapps di Tomcat. I web service saranno quindi accessibili all'URL
http://hostname:port/axis/...
E' possibile cambiare il nome di questo folder ma cambierà corrispondentemente anche l'URL. All'interno di webapps/axis si trova il folder WEB-INF in cui copiare le classi che si vogliono esporre come web service: i .class verranno copiati nel folder classes mentre i .jar nel folder lib. Prima di usare Axis è comunque necessario copiare un parser XML, Xerces o Crimson, in WEB-INF/lib. Ora Tomcat è configurato per esporre web service con Axis.
Un semplice web service In questa sezione si affronterà il problema del deploy di un web service con Axis mostrando tre casi di difficoltà crescente deploy di una classe Java con copia di file;
deploy della stessa classe mediante deployment descriptor;
deploy di un EJB;
Per i primi due esempi si userà la seguente classe Java che implementa un semplice sommatore
public class Calculator {
public int add(int x, int y) {
return x + y;
}
}
Per eseguire un deploy istantaneo della classe è sufficiente copiare il sorgente nel folder della web application di Axis con estensione jws, Java Web Service. A questo punto il servizio è immediatamente disponibile all'URL http://localhost:8080/axis/Calculator.jws E' il runtime di Axis che compila il file JWS in classe Java e inoltra quindi ad essa le chiamate SOAP.
Questa modalità è semplice e immediata ma non sempre utilizzabile; spesso il servizio di cui fare deploy non sarà implementato con una singola classe Java ed è inoltre necessario un modo per configurare i parametri di deploy come ad esempio il mapping dei tipi. Per questa ragione in Axis sono previsti i deployment descriptor, documenti XML che contengono le informazioni di deploy; segue come esempio il deployment descriptor per il servizio calculator
L'elemento service definisce appunto il web service a cui è stato dato il nome calculator. L'attributo provider permette di specificare il modo in cui il servizio viene esposto; in questo caso si usa il provider per una classe Java quindi si usa java:RPC come valore dell'attributo. L'elemento parameter permette di specificare i parametri di configurazione del servizio, in questo caso il nome della classe e i metodi esposti. Il deployment descriptor è contenuto in un file che ha in genere estensione wsdd. Quindi il deploy vero e proprio si ottiene mediante un tool a linea di comando: dopo aver incluso nel classpath axis.jar, commons-logging.jar, log4j-core.jar, jaxrpc.jar, tt-bytecode.jar e il parser XML si esegue
Questo processo può essere facilmente automatizzato usando ANT [3]. Fare deploy di un servizio su Axis consiste 'semplicemente' nel richiamare una classe Java con certi argomenti specificando le opportune librerie nel classpath. Ecco un target ANT che esegue proprio questo compito
Il codice presentato è abbastanza semplice viene creato un oggetto Service come punto di partenza per connettersi ad un web service SOAP; è possibile specificare un documento WSDL per ottenere informazioni sul servizio;
si crea quindi un oggetto Call che incapsula la chiamata vera e propria e si impostano le proprietà necessarie, in questo caso URL del servizio e nome del metodo da richiamare sul servizio. Si osservi che queste informazioni potrebbero essere ricavate dal WSDL;
a questo punto si impostano i parametri applicativi per l'invocazione del servizio inserendoli in un array di oggetti: in questo caso si tratta di una copia di interi; infine si invoca il servizio e si ottiene il risultato dell'operazione.
Il codice necessario per un client Axis è abbastanza semplice ma abbastanza verboso: è ad esempio abbastanza scomodo dover specificare i parametri del servizio come array di oggetti ed inoltre è necessario usare esplicitamente la API Axis. Nel seguito verrà mostrata una interessante soluzione fornita da Axis a questo problema.
EJB e web service
Un web service espone in genere logiche applicative implementate come EJB; in questa sezione si vedrà appunto come accedere via SOAP ad un EJB. Si supponga di voler realizzare un servizio che esponga i dati di una lista di attività. Il servizio verrà implementato come un session EJB stateless che espone un singolo metodo getList(): questo ritorna la lista delle attività come documento XML. Ecco la remote interface:
public interface TodoList extends EJBObject {
public String getList() throws RemoteException;
}
Questa è invece l'implementazione del metodo getList() contenuta nella classe TodoListEJB.java
...
public String getList() throws RemoteException {
return "<TodoList>" +
"<Task>Leggere la posta</Task>" +
"<Task>Riunione</Task>" +
"<Task>Corsa nel parco</Task></TodoList>";
}
...
Una implementazione reale avrebbe considerato identificativo e ruolo dell'utente per ricercare le attività in un database oppure interrogando un engine di workflow ma ai fini dell'esempio non sarebbe cambiato nulla. Ecco il deployment descriptor per l'ejb
Come si può vedere è stato indicato un provider di tipo java:EJB e vi sono più parametri per specificare il nome JNDI, le interfacce home e remote e infine le property JNDI per connettersi al server J2EE, in questo caso JBoss. A questo punto è possibile fare deploy del servizio e accedervi da un qualsiasi client SOAP. In precedenza è stato mostrato come accedere a un servizio usando JAX-RPC; nella sezione seguente si mostrerà come realizzare un client più evoluto basato su WSDL.
Axis e WSDL
WSDL (Web Services Description Language) è un linguaggio XML che descrive un web service, ovvero dove si trova, quali metodi espone e quali tipi di dato utilizza. Maggiori informazioni su WSDL si possono trovare in [4]. Axis offre un supporto completo a WSDL: innanzitutto è possibile ottenere il WSDL di un servizio in modo immediato con un browser e appendendo un "?WSDL" all'URL del servizio. Ad esempio accedendo all'URL http://localhost:8080/axis/services/todolist?WSDL si ottiene il seguente documento
Questa funzionalità è molto utile non solo perchè è semplice e immediata ma soprattutto perchè è indipendente da Axis e da Java: un qualsiasi client SOAP in grado di utilizzare WSDL si può collegare all'URL e usare il documento così generato per interrogare il servizio. Axis mette a disposizione anche un apposito tool a linea di comando, Java2WSDL, per ottenere il WSDL a partire da una classe Java. Lo stesso documento si può quindi ottenere con
dove i parametri hanno il seguente significato -o nome del documento WSDL da ottenere in output -l url del servizio -n namespace per il documento WSDL -p specifica la corrispondenza fra nome di package e namespace nome della classe che contiene l'interfaccia del servizio.
A partire dal documento WSDL è ora possibile utilizzare un altro tool, WSD2Java, che permette di generare le classi proxy da usare lato client; lo skeleton che fa da bridge fra il runtime di Axis e l'implementazione vera e propria del servizio.
Partendo dal documento WSDL precedente è possibile generare le classi da usare lato client nel modo seguente (nel classpath devono essere inclusi axis.jar, commons-logging.jar, jaxrpc.jar, wsdl4j.jar e il parser XML):
dove - o indica dove generare i sorgenti - p è il package che conterrà le
classi generate
Per il documento precedente vengono generate le seguenti classi all'interno del package com.mokabyte.javaxml.todolist.ws:
TodoList.java
Questa è l'interfaccia, che estende java.rmi.Remote, ottenuta dal portType e viene chiamata SDI, Service Definition Interface, in terminologia Axis.
TodoListService.java
Questa interfaccia viene derivata dal servizio definito nel documento WSDL.
TodoListServiceLocator.java
La classe locator implementa l'interfaccia di servizio e permette di ottenere un'istanza dello stub.
TodoListSoapBindingStub.java
Questa classe implementa l'interfaccia SDI, TodoList in questo caso, e contiene il codice che converte le invocazioni di metodi utilizzando la API di Axis. In questo modo vengono nascosti allo sviluppatore tutti i dettagli della chiamata SOAP.
Ecco un client che usa le classi generate
package com.mokabyte.javaxml.client.todolist;
import com.mokabyte.javaxml.todolist.ws.*;
public class TodoListClient {
public static void main(String args[]) throws Exception {
// Creazione del servizio
TodoListService service = new TodoListServiceLocator();
// Si ottiene uno stub
TodoList todolist = service.getTodolist();
// Invocazione vera e propria
String result = todolist.getList();
System.out.println(result);
}
}
Oltre alle classi da usare lato client è possibile generare anche gli skeleton lato server mediante le opzioni --server-side --skeletonDeploy true del generatore. Utilizzando tali switch verranno generati i file
TodoListSoapBindingImpl.java
Implementazione del servizio. Questa è un template che lo sviluppatore deve completare per accedere
TodoListSoapBindingSkeleton.java
Skeleton lato server che si pone fra l'engine Axis e l'implementazione del servizio.
deploy.wsdd e undeploy.wsdd Deployment descriptor per il deploy e l'undeploy del servizio.
Nell'esempio presentato non si è fatto uso di questa feature ma si è fatto deploy direttamente dell'EJB.
WSDL2Java è un tool molto importante poichè permette di semplificare notevolmente lo sviluppo di un client Java per un web service: non solo si riduce la quantità di codice da scrivere ma questo non fa alcun riferimento alla API Axis o JAX-RPC.
Monitoring
Per verificare il corretto funzionamento di un web service Axis mette a disposizione una comoda utility, TCPMon, che permette di monitorare il traffico di rete generato dal servizio. Lo si lancia con
java org.apache.axis.utils.tcpmon
Appare quindi la seguente interfaccia per l'inserimento dei parametri
Figura 1: Form di inserimento parametri
utilizzando il tool come Listener si devono impostare
Listen Port #: numero di porta su cui TCPMon si pone in ascolto per le richieste Target Hostname: host su cui inoltrare le richieste Target Port #: il numero di porta utilizzato dall'host target
A questo punto il pulsante Add viene aggiunto un tab con le informazioni sulla connessione inserita:
Figura 2: Informazioni sulla connessione monitorata
E' possibile inserire altre serie di parametri per monitorare altre connessioni. I pannelli Request e Response mostrano i messaggi scambiati ad ogni connessione. Ad esempio invocando il servizio calculator si hanno i seguenti
In questo modo si ha un completo controllo del traffico di rete generato da un web service.
Client Visual Basic
Poiché il vero valore aggiunto di un web service è l'interoperabilità fra linguaggi e piattaforme diverse si mostrerà ora un client Visual Basic per il servizio todolist:
Option Explicit
Private Sub Form_Load() Dim client As SoapClient30 Set client = New MSSOAPLib30.SoapClient30 client.MSSoapInit "http://localhost:8080/axis/services/todolist?WSDL"
Dim list As String
list = client.getList()
MsgBox list
End Sub
Il codice precedente utilizza la libreria SOAP 3.0 di Microsoft utilizzando il documento WSDL esposto dal runtime Axis.
Conclusioni
Axis è un toolkit con molte caratteristiche interessanti, in particolare il supporto a WSDL che semplifica notevolmente l'integrazione con altri sistemi, come dimostrato dal client sviluppato in VB. Il generatore di codice semplifica poi notevolmente lo sviluppo di client Java. Axis risulta quindi essere un importante strumento per lo sviluppatore Java.
Bibliografia
[1] Andrea Giovannini - "SOAP e Java", http://www.mokabyte.it/2001/01/soap.htm
[2] Apache Group - "Axis", http://xml.apache.org/axis
[3] Apache Group - "ANT", http://jakarta.apache.org/ant
[biografia autore] Andrea Giovannini si occupa di architetture per applicazioni enterprise Web-based con tecnologia J2EE, con particolare interesse per XML.
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