Articoli Manifesto Tools Links Canali Libri Contatti ?
Web / Web Services

Realizzare un Web Services in pochi minuti con Apache Axis

Abstract
Viene illustrato il framework di sviluppo per i Web Service Apache Axis e mostrato come realizzare un semplice Web Service con strumenti open source e con il linguaggio Java.
Data di stesura: 11/09/2004
Data di pubblicazione: 13/10/2004
Ultima modifica: 04/04/2006
di Rudi Verago Discuti sul forum   Stampa

Di cosa parliamo?

I Web Services (WS) rivoluzioneranno il mondo dell'informatica grazie all'uso del linguaggio XML: questo oramai lo abbiamo capito, ma come facciamo allora a sviluppare WS?

Innanzitutto scegliete il vostro linguaggio di programmazione preferito: se la vostra scelta è Java allora quasi d'obbligo è l'uso di Apache Axis su Tomcat. Axis è il framework di sviluppo per i WS mentre Tomcat è l'application server dove avviene l'esposizione dei WS.

L'Axis nella manica

Axis permette lo sviluppo di WS sia in Java che in C++ ma noi ci occuperemo solo del linguaggio di casa Sun, Java implementa gli standard:

  • JAX-RPC: insomma SOAP con il classico RPC
  • SAAJ: permette di manipolare il messaggio SOAP e gestire gli attachment
  • tanti altri...

Axis implementa quindi il modello JAX-RPC e supporta anche SAAJ, per un maggiore approfondimento vedi articolo precedente. Non tutto nasce però da Apache, il prodotto iniziale è merito di IBM, che poi molto gentilmente decise di regalare al consorzio Apache tutto il codice. Viene alla luce quindi Apache SOAP e poi la sua evoluzione: Apache Axis.

Le caratteristiche più importanti del framework sono:

  • implementazione SOAP 1.1/1.2
  • supporto JWS (Java Web Services): permette un facile e immediato deploy dei WS
  • supporto serializzazione/de-serializzazione
  • implementazione WSDL
  • utility WSDL2Java e Java2WSDL
  • Soap Monitor e TCP Monitor: due applicazioni scritte in Java che permettono di monitorare il traffico SOAP
  • possibilità di usare tre differenti metodi per l'invocazione dei WS: Dynamic Invocation Interface, Stub generato dal WSDL e Dynamic Proxy

I componenti di Axis sono quindi: un engine per l'elaborazione dei messaggi SOAP, handler per la gestione dei messaggi, vari meccanismi di deploy, serializzazione/de-serializzazione, configurazione e di trasporto dei messaggi.

Il server servente

Come primo passo è necessario aver configurato Java su una macchina Linux. È possibile scaricarsi dal sito della Sun [1] il pacchetto in vari formati: l'installazione è molto semplice ed avviene tramite una wizard grafica. Al termine dell'installazione è necessario settare le variabili di sistema $JAVA_ HOME e $PATH, che contengono rispettivamente il percorso della directory d'installazione di JAVA e degli eseguibili, come ad es.:

export JAVA_HOME=/usr/java/jdk1.5.0
export PATH=$PATH:$JAVA_HOME/bin

Per quanto riguarda Axis è sufficiente scaricarsi il pacchetto dal sito [2] e scompattarlo (io consiglio sempre /opt/axis, da questo momento in poi farò riferimento a questa directory).

L'installazione di Tomcat avviene con le modalità classiche (compilazione o RPM, anche in questo caso considero come home di Tomcat la directory /opt/tomcat). Esistono comodi script per l'avvio e l'arresto dell'application server che si trovano in $CATALINA_HOME/bin.

La verifica della corretta configurazione si ottiene digitando nel browser e verificando la comparsa della home page Tomcat.

Axis si integra molto semplicemente con Tomcat: l'unica operazione da eseguire è la copia della directory webapps/axis (nella home di Axis, quindi /opt/axis/webapps/axis) all'interno di webapps (nella home di Tomcat, quindi /opt/tomcat/webapps). Successivamente, per comodità, si possono configurare un po' di variabili globali:

export CATALINA_HOME=/opt/tomcat
export JAVA_ENDORSED_DIRS=$CATALINA_HOME/bin:\
$CATALINA_HOME/common/lib:\
$CATALINA_HOME/webapps/axis/WEB-INF/lib
export AXIS_HOME=/opt/axis
export AXIS_LIB=$AXIS_HOME/lib
export AXISCLASSPATH=$AXIS_LIB/axis.jar:\
$AXIS_LIB/commons-discovery.jar:\
$AXIS_LIB/commons-logging.jar:\
$AXIS_LIB/jaxrpc.jar:\
$AXIS_LIB/saaj.jar:\
$AXIS_LIB/log4j-1.2.8.jar:\
$AXIS_LIB/xml-apis.jar:\
$AXIS_LIB/xercesImpl.jar

La variabile $AXISCLASSPATH rappresenta i riferimenti alle librerie jar che contengono l'implementazione degli standard sui WS come SAAJ e JAX-RPC; osservate l'ultima libreria dove è incluso il parser XML Xerces, Java include il parser Crimson ma Apache consiglia Xerces: entrambi funzionano adeguatamente quindi la scelta è puramente personale.

Eventualmente potreste settare un'ulteriore variabile globale $CLASSPATH che contiene il percorso di altre librerie, io di solito copio tutti i jar che mi servono in $CATALINA_HOME/common/lib ma ognuno può adottare il metodo che preferisce.

In alcuni casi potrebbe essere necessario l'uso della libreria activation.jar, che può essere scaricata comodamente dal sito della Sun.

La verifica della corretta integrazione tra Axis e Tomcat si ottiene facendo puntare il browser http://localhost:8080/axis: dovrebbe compare la semplice home page testuale di Axis da cui è possibile effettuare alcune operazioni.

Coding: lato server

Apache AXIS implementa, come già accennato, il nuovo standard JWS di Java che permette di effettuare il deploy di un WS in maniera semplice e veloce. È sufficiente sviluppare la propria classe in Java, testarla, cambiare l'estensione da .java e .jws e il WS è pronto: niente di più immediato. Axis lo tratterà in maniera simile ad una JSP ossia lo compilerà e si occuperà dell'interfacciamento con SOAP mediante la conversione automatica SOAP-JAVA. Tale metodo ha ovviamente il pregio della semplicità a scapito della flessibilità: è infatti impossibile decidere quali metodi esporre e specificare conversioni specifiche tra SOAP e JAVA. Un metodo più flessibile è l'uso dei file WSDD (Web Service Deployment Descriptor), introdotti da Axis, ma per ``il primo'' WS l'uso del JWS è più che adeguato. Un WS accessibile è quindi una classe Java che espone i propri metodi pubblici e non-static.

Scriviamo ora una semplice classe di esempio che controlla se un numero è pari oppure dispari: l'esempio è ovviamente molto semplice (direi ridicolo ma non volevo fare il solito esempio del saluto ``Hello User, I'm your WS''), ma potrebbe essere il primo metodo di una classe matematica che si occupa di effettuare appunto calcoli matematici. Il metodo pari restituisce un valore di tipo String.

  1. public class matematica 
  2.   public String pari(int numero) 
  3.     return (numero % 2) == 0 ? "pari" : "dispari"; 

Chiamiamo il file matematica.jws e copiamolo nella directory $CATALINA_HOME/webapps/axis. Ora è necessario eseguire il deploy, ovvero quella operazione che permette di rendere disponibile il nostro WS ottenendo il file WSDL descrittore del WS.

Per ottenere questo e verificare la corretta interpretazione e compilazione dei WS si digiti nel browser: http://localhost:8080/axis/matematica.jws?WSDL.

Il file WSDL ottenuto è il seguente:

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions
  targetNamespace="http://localhost:8080/axis/matematica.jws"
  xmlns="http://schemas.xmlsoap.org/wsdl/"
  xmlns:apachesoap="http://xml.apache.org/xml-soap"
  xmlns:impl="http://localhost:8080/axis/matematica.jws"
  xmlns:intf="http://localhost:8080/axis/matematica.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:message name="pariResponse">
    <wsdl:part name="pariReturn" type="xsd:string"/>
  </wsdl:message>
  <wsdl:message name="pariRequest">
    <wsdl:part name="numero" type="xsd:int"/>
  </wsdl:message>
  <wsdl:portType name="matematica">
    <wsdl:operation name="pari" parameterOrder="numero">
      <wsdl:input message="impl:pariRequest" name="pariRequest"/>
      <wsdl:output message="impl:pariResponse" name="pariResponse"/>
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="matematicaSoapBinding" type="impl:matematica">
    <wsdlsoap:binding style="rpc"
      transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="pari">
      <wsdlsoap:operation soapAction=""/>
      <wsdl:input name="pariRequest">
        <wsdlsoap:body
          encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
          namespace="http://DefaultNamespace" use="encoded"/>
      </wsdl:input>
      <wsdl:output name="pariResponse">
        <wsdlsoap:body
          encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
          namespace="http://localhost:8080/axis/matematica.jws" use="encoded"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="matematicaService">
    <wsdl:port binding="impl:matematicaSoapBinding" name="matematica">
      <wsdlsoap:address location="http://localhost:8080/axis/matematica.jws"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

È immediato vedere come il file sia di facile lettura, ad esempio si possono individuare:

  • wsdl:message: indicano il tipo dei dati scambiati, int in ingresso e string in uscita
  • wsdl:portType: il tipo di operazione e i parametri
  • wsdl:bindings: il tipo di protocollo usato
  • wsdl:service: caratteristiche del WS come l'indirizzo

Il WS è completamente realizzato ed esposto, ossia accessibile ... ma ora come possiamo interrogarlo?

Il client ordina ed ottiene

Ci sono varie tecniche di interfacciamento al WS e molte di queste usano come informazione il file WSDL generato (Stub) e reso disponibile dal server: tali tecniche non sono immediate, noi come primo esempio useremo invece la Dynamic Invocation che non fa uso del WSDL.

Prima di tutto dovete però armarvi di buona pazienza e, come nel server, impostare la variabile d'ambiente $AXISCLASSPATH

Ecco il semplice codice del client:

  1. import org.apache.axis.client.Call; 
  2. import org.apache.axis.client.Service; 
  3. import org.apache.axis.encoding.XMLType; 
  4. import org.apache.axis.utils.Options; 
  5. import java.net.URL; 
  6. import javax.xml.rpc.ParameterMode; 
  7.  
  8. public class clientMatematica 
  9.   public static void main(String[] args) throws Exception 
  10.     // 
  11.     Integer numero  = new Integer(args[0]); 
  12.     String nameWS   = "http://localhost:8080/axis/matematica.jws"; 
  13.     URL endPointWS  = new URL(nameWS); 
  14.  
  15.     //inizializzazione WS 
  16.     Service service = new Service(); 
  17.     Call call       = (Call)service.createCall(); 
  18.     call.removeAllParameters(); 
  19.  
  20.     //configurazione parametri WS 
  21.     call.setTargetEndpointAddress(endPointWS); 
  22.     call.addParameter("numero", XMLType.XSD_INT, ParameterMode.IN); 
  23.     call.setOperationName("pari"); 
  24.     call.setReturnType(XMLType.XSD_STRING); 
  25.  
  26.     //invocazione WS 
  27.     String risultato = (String)call.invoke(new Object[]{numero}); 
  28.  
  29.     // 
  30.     System.out.println("Il numero " + numero + " e' " + risultato); 

La lettura del codice è agevole:

  • istanziazione degli oggetti Call e Service
  • configurazione dell'endpoint: in questo caso l'indirizzo del WS (setTargetEndpointAddress)
  • indicazione tipo parametri d'ingresso (addParameter)
  • indicazione del nome del metodo da invocare (setOperationName)
  • indicazione tipo parametri d'output (setReturnType)
  • indicazione parametri e invocazione del metodo (invoke)
  • gestione del risultato

E di seguito compilazione, avvio ed output:

# javac -classpath $AXISCLASSPATH clientMatematica.java

# java -cp $AXISCLASSPATH clientMatematica 5
Il numero 5 e` dispari

Il messaggio SOAP inviato dal client al serve dovrebbe assomigliare a qualcosa di simile:

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns:SOAPENV="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <SOAP-ENV:Body>
    <ns1:pari xmlns:ns1="http://localhost:8080/axis/matematica.jws">
      <arg0 xsi:type="xsd:int">5</arg0>
    </ns1:pari>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

mentre la risposta è:

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns:SOAPENV="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <SOAP-ENV:Body>
    <ns1:pariResponse xmlns:ns1="http://localhost:8080/axis/matematica.jws">
      <arg0 xsi:type="xsd:string">dispari</arg0>
    </ns1:pariResponse>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Non commento i due messaggi SOAP per non insultare la vostra intelligenza, infatti sono solo indicati i parametri e il WS esposto.

Tutto molto semplice, fin troppo semplice. Vi ricordo però che questa metodologia è la meno flessibile poiché non considera il file WSDL e quindi non permette un'automatizzazione della procedura.

L'uso del JWS, come già illustrato, ha delle limitazioni poiché si deve disporre del codice sorgente e rende impossibili gestioni personalizzate: un risultato maggiormente scalabile si ottiene ricorrendo al WSDD e le utility WSDL2Java e Java2WSDL.

I WS presentano vari problemi di sicurezza: primo tra tutti sono testo HTTP in grado di invocare metodi e passare inosservati attraverso i firewall. Sono allo studio vari protocolli di sicurezza, alcuni sono già disponibili e completamente funzionanti ma risulta difficile applicarli ad una piccola realtà.

È per questo che la prima generazione di WS non ha tecniche di sicurezza ad-hoc ma usa modalità ereditate dal vecchio HTTP: ossia i tunnel SSL/TLS over HTTP, insomma il cosiddetto HTTP-Secure (HTTPS).

Per usare HTTPS, poiché i WS risiedono su un application server, si deve come prima cosa configurare Tomcat per accettare connessioni cifrate.

Si deve creare un certificato per il server tramite l'utility keytool di Java,

successivamente si deve configurare il web server in modo tale che accetti connessioni https sulla porta 8443 modificando il file di impostazioni server.xml inserendo/de-commentando le seguenti righe:

<!--Define a SSL Coyote HTTP Connector on port 8443 --> 
< Connector port="8443"
  maxThreads="150"              minSpareThreads="25"
  maxSpareThreads="75"          enableLookups="false" 
  disableUploadTimeout="true"   acceptCount="100" 
  debug="0"                     scheme="https" 
  secure="true"                 clientAuth="false" 
  sslProtocol="TLS"                                   />

La correttezza della procedura può essere verificata controllando:
https://localhost:8443/axis/matematica.jws

Ora il client deve interrogare il server WS sulla porta 8443: ciò può avvenire in due modi differenti:

  • autenticazione one-way (stile browser per intederci): solo il server ha il certificato, allora si devono riscrivere (vuoti) un paio di metodi Java
  • autenticazione two-way: il server genera un certificato anche per il client, quest'ultimo deve richiamarlo nel codice.

Ma vi sto dicendo già troppo ... comunque il prossimo articolo riguarda la sicurezza nei WS ... quindi basta aspettare ... insomma abbiate un po' di pazienza ...

Informazioni sull'autore

Rudi Verago, Laureato in ingegneria informatica con una breve esperienza come consulente in ambito Linux e sicurezza digitale. È da una vita appassionato di programmazione e protocolli di comunicazione. Ha esperienza inoltre come amministratore reti miste wireless-cablate (Linux e Windows), e ha all'attivo una pubblicazione scientifica. Ama l'approccio teorico ai problemi.
Maggiori informazioni sul suo sito personale.

È possibile consultare l'elenco degli articoli scritti da Rudi Verago.

Altri articoli sul tema Web / Web Services.

Risorse

  1. Il sito ufficiale di Java.
    http://java.sun.com
  2. Il sito di Axis della Apache Software Foundation.
    http://xml.apache.org/axis
  3. Il sito di Tomcat della Apache Software Foundation.
    http://apache.tomcat.org
  4. Web Services I, il portale dei WS.
    http://www.webservices.org
  5. Web Services II, molti articoli e libri direttamente dal grande O'Reilly.
    http://webservices.xml.com
  6. Vlain.ing, il sito personale dell'autore.
    http://vlain.altervista.org
Discuti sul forum   Stampa

Cosa ne pensi di questo articolo?

Discussioni

Questo articolo o l'argomento ti ha interessato? Parliamone.