Web Services con Eclipse 3.4, Tomcat 6.0.16 e Axis2 1.4

Per un progetto in azienda sto lavorando con i web services, usiamo pero’ vecchie versioni di eclipse e axis2 poichè il progetto è iniziato con quelle versioni e non si può cambiare strumento durante lo sviluppo, come è giusto che sia. Per i fatti miei però ho sperimentato la generazione di web services dapprima con Netbeans 6.1 e poi con Eclipse 3.4.

Introduzione

Come da titolo dovete scaricare Eclipse, Tomcat e Axis2. Io ho scaricato Eclipse 3.4 per Java EE, Tomcat Core e Axis2 il file war ma anche la standard binary distributition perchè essa contiene dei comandi che il war file non ha.

Tomcat è un application server e dovrà lanciare Axis2 che funge da contenitore per i vostri web services e vi permette anche di gestirli. Con Eclipse dovrete creare le classi java per il client e il server.

Iniziamo

Una volta estratta la standard binary distribution, create la variabile di ambiente AXIS2_HOME in modo che punti ad essa e poi copiate il file war nella cartella /webapps di Tomcat. Ora, se volete, potete far partire tomcat lanciandolo dalla sua cartella /bin e con il vostro browser andare all’url:

http://localhost:8080

8080 è in genere la porta su cui Tomcat gira. Dovreste vedere la pagina di Tomcat, se cliccate a sinistra su Tomcat manager vedete la lista di applicazioni tra cui c’è Axis2. Cliccateci sopra e vi compare la pagina di Axis2. Come primo link c’è “Services” che indica gli attuali web services che stanno girando tra cui ci sarà anche il nostro.

Come vi ho già detto nella standard binary distribution ci sono dei comandi che nel war non sono presenti e sono java2wsdl e wsdl2java (vedere qui per tutti i parametri)

Se siete nuovi nel mondo dei web services dovete sapere che i file wsdl sono dei file xml che descrivono i web services percio’ prima di proseguire vi consiglio di studiarvi XML, i file xml schema e i file wsdl in generale (potete dare una occhiata al sito w3schools). Occorre saperlo perchè grazie al comando wsdl2java potete creare, a partire dal file wsdl, ciò che sta sotto la comunicazione tra client e webservice ovvero stub e skeleton.

Stub e skeleton sono delle classi java che fungono da proxy ovvero il vostro client chiamerà lo stub per la comunicazione mentre il webservice userà lo skeleton per ricevere, ed eventualmente trasmettere, i dati.

In un precedente articolo ho spiegato come potete validare i vostri file wsdl in modo da diminuire i rischi di interoperabilità, pensate ad esempio ad un client (stub) realizzato in java ed un web service (skeleton) realizzato sotto .NET.

Il comando java2wsdl potete immaginare cosa fa.

Questi comandi, come descritto nella reference di Axis2 sono molto semplici da usare ma una interfaccia grafica non dispiace.

Il servizio andrà poi impacchettato in un archivio axis (file aar) e deployato (in altre parole copiato e spacchettato, lasciatemi passare il termine) nella cartella di Axis2 sotto Tomcat.

Ho dapprima provato il plugin di Netbeans ma personalmente credo che andrebbe migliorato perchè è possibile selezionare poche cose e, inoltre, obbliga alla all’inserimento di parametri (-g) a linea di comando (da dentro l’interfaccia!) per la generazione del client, in quanto, in automatico, lui crea lo skeleton e l’unico modo per creare lo stub è aggiungere il parametro; per il resto il plugin si comporta bene. Il tutorial che ho seguito è questo. Tuttavia ho poi proseguito per Eclipse anche se poi ho scoperto che il plugin è buggato ma ho trovato rimedio.

I plugin di Axis2 sono a mio avviso più completi e si scaricano dal sito di Axis2 e precisamente sono il Service Archive Wizard 1.4 e il Code Generator Wizard 1.4 che come vedete nella tabella richiedono Axis 1.4.

Il primo serve per creare l’archivio axis da copiare in Tomcat il secondo come interfaccia per i comandi java2wsdl e wsdl2java.

Non dovete fare altro che scaricare i plugin ed estrarli nella cartella plugins di Eclipse e correggere qualche bug :-) .

In pratica nella cartella del Code Generator c’è un file che si chiama plugin.xml, in questo file sono descritte le librerie di cui il plugin si serve, tra queste notate che c’è l’archivio jar stax-api-1.0.1.jar ma questo non si trova nella cartella lib del plugin e dovete scaricarlo dalla rete (vedete qui). C’è poi un pacchetto che manca proprio e che è backport-util-concurrent-3.1.jar (lo trovate nella cartella /lib di Axis2) che dovete aggiungere nella cartella lib e nel file plugin.xml (in pratica tutto cio’ serve per risolvere l’eccezione java.lang.reflect.invocationTargetException che si manifesta all’ultimo passaggio del wizard).

Nel caso in futuro avete degli errori lanciate Eclipse in debug mode da console in questa maniera:

eclipse -clean -debug

L’opzione debug vi permette di vedere eventuali errori da console, clean pulisce una cache che Eclipse usa quando crea i vostri progetti (per altri parametri vedere qui). Se ancora avete problemi come ultima speranza rimuovete il plugin che vi da fastidio dalla cartella nascosta .metadata/.plugins che si trova nel vostro workspace.

Non fate partire ancora Eclipse perchè voglio segnalarvi un altro plugin che vi permette di lanciare/fermare Tomcat da Eclipse questo plugin lo trovate qui ed è semplice da installare come spiega il sito (in pratica va poi messo nella cartella dropins di Eclipse e occorre configurare il plugin indicando il path di tomcat).

Ok ora siete pronti per lanciare Eclipse, dovrete creare un progetto java e seguire questa guida suddivisa in 2 parti che vi spiega per filo e per segno tutto.

Durante la guida vi ritrovete a creare il codice java per lo stub dal file wsdl, il wizard vi chiede l’inclusione delle librerie del codegen ma questa non va e perciò dovrete farlo a mano agggiungendole direttamente nel vostro Build Path prendendole dalla cartella lib del plugin Codegen. Attenzione potrebbe essere un problema del Mac, ho notato che in debug mode, al momento della creazione del codice eclipse pensa di trovare il plugin nella cartella /eclipse/Contents/MacOS/plugins e non, come dovrebbe essere, in /eclipse/plugins, perciò se siete sotto Mac copiate i 2 plugin anche in quella cartella (da creare) e cosi al momento della generazione pesca correttemente i jar file della cartella lib.

Se non vedete il codige generato provate a fare un refresh del progetto. Volevo farvi notare che quando il wsdl viene caricato il plugin carica anche gli XML schema collegati (se ve ne sono) e quindi fa un controllo sulla validità, potete notare il caricamento se usate Eclipse in debug mode; tra l’altro una volta che avete creato il file wsdl potete validarlo selezionandolo e cliccando sulla voce di validazione dal menu contestuale aperto con il tasto destro del mouse.

Quando vi viene chiesto di compilare fatelo usando il file build.xml (tasto destro ed “esegui” dal menu contestuale) che viene automaticamente generato e conosce tutte le dipendenze.

Quando eseguirete il client avrete una eccezione riguardo il file jar woden API che è mancante questo perchè con Axis 2 1.4 questo package è richiesto; prendetelo dalla cartella lib di Axis2 e aggiungetelo al vostro build path. Ho semplicemente aggiunto solo il jar delle woden API.

Non vi preoccupate del warning su log4j è perchè non trova il suo file di configurazione.

Quando andate a generare lo skeleton che dovete riempire fate caso al fatto che i parametri in ingresso del metodo terminano con un numero.

Notate anche che quando generate lo stub questo ha come sottoclassi le richieste e le risposte mentre quando generate lo skeleton queste sono messe nei rispettivi file.

Nella parte 2 del tutorial vi verrà chiesto di usare il file services.xml che è stato generato nella cartella resources, ebbene in teoria dovreste poterlo selezionare in pratica dovrete inserire il suo path a mano.

Tra l’altro vi faccio notare che, sempre nella parte 2, il file wsdl viene generato nuovamente nella cartella resources, il file è pressocchè identico a quello di partenza anche se è questo che viene usato per la generazione del servizio con il Service Archiver.

Nella parte 2 vi viene chiesto di inserire la parte del client ebbene inserite il codice usato nella parte 1 e non quello proposto.

Se siete arrivati fino alla fine del tutorial complimenti! La strada per connettere e dare più funzionalità ai web services è lunga ma ora avete la basi per poterne creare.

Aggiornamento 1

Se avete avuto occasione di creare da zero wsdl, avete visto la comoda possibilità di includere XML schema dentro in modo da separare la descrizione del servizio dai tipi usati nei messaggi.

In questo ambito ho scoperto che il plugin Service Archiver ha un bug, semplicemente non include l’XML schema usato dal file WSDL dentro l’archivio aar creato e dovete purtroppo farlo a mano, a meno che c’è qualcuno che vuole modificare il codice (dovrebbe essere semplice ma non ho voglia, considerate che c’è la libreria WSDL4J che puo’ aiutarvi). Per modificarlo spacchettare il file aar (una volta rinominato in zip), aggiungete il file e rimpacchettate.

Aggiornamento 2 (uso di Xmlbeans su Eclipse 3.2, Tomcat 6 e Axis2 1.3, da verificare con Axis2 1.4)

Se durante la creazione del web service avete usato Xmlbeans come data binding ovete prestare attenzione a 2 cose in caso di errore:

-) La cartella resources contiene una cartella generata da Xmlbeans che si chiama schemaorg_apache_xmlbeans. Questa cartella contiene la cartella system la quale a sua volta contiene delle cartelle indicate da una combinazione di numeri. In una di queste si deve trovare il file TypeSystemHolder.class, questo file potrebbe esservi richiesto quando lanciate il client. Dovete quindi aggiungere la cartella resources come Class Folder tra le librerie del progetto e non come src folder.

-) In fase di creazione del web service con il Service Archiver Wizard potreste aver bisogno di aggiungere tra le librerie esterne quelle di di Xmlbeans ovvero il file Xbeans-packaged.jar che si trova nella cartella build/lib.

Alla prossima

P.S. Ho usato la java virtual machine 1.5.0_13

22 thoughts on “Web Services con Eclipse 3.4, Tomcat 6.0.16 e Axis2 1.4

  1. Figurati, anche io cerco in rete e risolvo problemi, poi cerco di spiegare i problemi che ho avuto.

    Ti consiglio di vedere gli altri articoli:

    -Web services e interoperabilità
    -Fare il debug di web services
    -Axis2 e la gestione dei soap header
    -Junit e SoapUi, strumenti per testare web services

    che aiutano per fare altre cose

  2. Ciao, grazie mille per la guida, ma purtroppo l’errore java.lang.reflect.invocationTargetException continua ad esistere, anche aggiungendo le librerie che hai scritto e le correzioni nel file plugin.xml
    Uso eclipse ganymede con axis2 1.4
    Ho controllato il file plugin.xml e ho inserito altre librerie che erano presenti nel file xml ma non nella cartella lib, ma niente lo stesso.
    Sai se c’è qualcos’altro che posso fare?
    Grazie mille

  3. Ok grazie ho risolto da solo,
    ho ripetuto più volte i passaggi che hai scritto tu nel tutorial e dopo un pò di giri è funzionato tutto…i misteri dell’informatica ;)

  4. ciao kaosktrl, Complimenti per la guida
    Arrivo Felicemente alla fine, tutto perfetto, ma quando runno il client (come java application):
    log4j:WARN No appenders could be found for logger (org.apache.axis2.description.AxisService).
    log4j:WARN Please initialize the log4j system properly.
    Exception in thread “main” java.lang.NoClassDefFoundError: org/apache/woden/resolver/URIResolver
    at org.apache.axis2.deployment.ModuleDeployer.deploy(ModuleDeployer.java:60)
    at org.apache.axis2.deployment.repository.util.DeploymentFileData.deploy(DeploymentFileData.java:136)
    at org.apache.axis2.deployment.DeploymentEngine.doDeploy(DeploymentEngine.java:597)
    at org.apache.axis2.deployment.RepositoryListener.loadClassPathModules(RepositoryListener.java:195)
    at org.apache.axis2.deployment.RepositoryListener.init2(RepositoryListener.java:70)
    at org.apache.axis2.deployment.RepositoryListener.(RepositoryListener.java:63)
    at org.apache.axis2.deployment.DeploymentEngine.loadFromClassPath(DeploymentEngine.java:164)
    at org.apache.axis2.deployment.FileSystemConfigurator.getAxisConfiguration(FileSystemConfigurator.java:135)
    at org.apache.axis2.context.ConfigurationContextFactory.createConfigurationContext(ConfigurationContextFactory.java:68)
    at org.apache.axis2.context.ConfigurationContextFactory.createConfigurationContextFromFileSystem(ConfigurationContextFactory.java:184)
    at org.apache.axis2.client.ServiceClient.configureServiceClient(ServiceClient.java:150)
    at org.apache.axis2.client.ServiceClient.(ServiceClient.java:143)
    at ws.example.TemperatureConverterStub.(TemperatureConverterStub.java:103)
    at ws.example.TemperatureConverterStub.(TemperatureConverterStub.java:89)
    at ws.example.TemperatureConverterStub.(TemperatureConverterStub.java:140)
    at ws.example.TemperatureConverterServiceClient.main(TemperatureConverterServiceClient.java:8)

    PERCHEEEEEEEEEEEEEEEEEEEE????
    PS: Uso eclipse ganymede, tomcat 5.5 e axis2 1.4

  5. L’errore indica che non trova il package woden, dovresti provare ad aggiungerlo alle librerie del tuo progetto. Se lo hai già fatto è un altro discorso.

  6. Ciao kaosktrl,
    scusa se irrompo in questa conversazione, ma ho un problemone con axis2 che proprio non riesco a risolvere e magari puoi darmi una mano.
    Il mio problema è questo:
    se lancio il web service che ho creato con Eclipse (deployato sulla mia applicazione web) da una classe esterna che ha un main funziona tutto e il servizio viene invocato correttamente.
    Se effettuo la stessa identica operazione invocando la il servizio dall’interno della web application, passando sempre per la stessa classe che precedentemente lanciavo dal main, ma questa volta passando per un metodo della classe stessa non mi funziona niente!!!

    Questo è l’xml generato nel caso che funziona:

    058091
    2007
    2008-09-09T12:36:12.031Z
    c://cdc_config/provezip/torino2007OK.zip
    torino2007OK.zip
    prot01

    2008-09-09Z
    1
    Rendiconto di gestione

    E questo l’xml generato nel caso che non funziona:

    058091
    2007
    2008-09-09T12:36:12.031Z
    c://cdc_config/provezip/torino2007OK.zip
    torino2007OK.zip
    prot01

    2008-09-09Z
    1
    Rendiconto di gestione

    Come puoi notare nel caso non funzionante c’è in più un Header, quello che non capisco è perchè nel primo caso non viene generato mentre nel secondo si, se le classi che lo generano sono le stesse!!!

    Qualsiasi aiuto mi sarebbe molto utile

    Ciao grazie

  7. Scusate qualcuno mi sa dire come usare i parametri di input\output con axis2…
    ho definito il metodo

    public int metodo(Holder inout, String a) { …}

    ma non funziona

    grazie

  8. Ciao,
    volevo dare il mio contributo a questo ottimo post almeno per quanto è stata la mia esperienza.

    Ho seguito tutto come nella guida ed i suggerimenti per la risoluzione dei problemi, ma nel mio caso l’errore “java.lang.reflect.invocationTargetException” continuava ad esserci.

    Ho risolto dopo ore di ricerca su google ed ho trovato la soluzione aggiungendo anche il file geronimo-stax-api_1.0_spec-1.0.1.jar presente nella lib nell’addin Axis2-1.4.1, nella lib Axis2_Codegen_Wizard_1.4.0 oltre ad aggiungerlo come per gli altri nel file xml plugin.

    Ho utilizzato la versione Axis2 1.4.1, Tomcat 6.x su MacOSX 10.5.6
    ciao
    Ale

  9. Pingback: Axis2, questo sconosciuto « Appunti di tutto

  10. Ciao!
    Mi sapreste dire come sia possibile che con l’esempio “TemperatureConverter” non ricevo l’errore java.lang.reflect.invocationTargetException mentre con un altro mio progetto SI !?!?!?!?!? *_*
    eclipse-jee-ganymede-SR2-win32_1
    axis21.4

  11. Prima di tutto grazie per l’aiuto, per iniziare questo articolo è stato utilissimo, senza molti problemi sono riuscito a costruire service e client… le uniche difficoltà le ho avute con web services sotto https, fortunatamnete ho risolto.
    Ora però in tutti gli esempi che ho trovato i web service lato server sono semplici e non fanno nessun controllo sui client. Mi spiego meglio il problema che ho è che devo fare un web service che deve controllare, prima di terminare, se il client è ancora in attesa e non sia andato in time out.
    Mi è successo questo: il clent a volte è possinbile che vada in time out, quindi si blocca e non fa delle operazioni. Il server invece conclude (anche se in ritardo) sempre le operazioni (e non posso allungare i tempi di attesa del client). Come posso sapere ad un certo punto se il client è amncora in attesa?
    grazie

    • :-) felice che ti sia stato utile, lo scrissi tempo fa e ora non lavoro più con i web services ma conto presto di tornarci su

  12. Ciao! Grazie infinite per questa guida! Sono giorni che sbatto la testa contro il muro nella speranza di far funzionare i web services spero che grazie ai tuoi consigli riesca a risolvere!

  13. Salve a tutti! Grazie per la guida, mi è stata di grande aiuto :)
    Ti volevo chiedere una cosa….ho creato un mio WS solo che ora vorrei aggiungere una policy di sicurezza che richieda, per esempio, l’uso di username e password…
    Ho provato a fare delle ricerche su google ma non sono riuscita a trovare nessuna policy con il codice completo sia lato server che lato client…
    Per l’implementazione del WS security utilizzo rampart….
    Grazie a buona giornata :)

  14. Quando compilo il file build.xml mi esce questo errore

    Buildfile: D:\Universita\Web Service\esempio\build.xml
    init:
    pre.compile.test:
    [echo] Stax Availability= true
    [echo] Axis2 Availability= true
    compile.src:
    [javac] Compiling 1 source file to D:\Universita\Web Service\esempio\build\classes
    [javac] D:\Universita\Web Service\esempio\src\org\example\www\esempio\PWCBHandler.java:2: package org.apache.ws.security does not exist
    [javac] import org.apache.ws.security.WSPasswordCallback;
    [javac] ^
    [javac] D:\Universita\Web Service\esempio\src\org\example\www\esempio\PWCBHandler.java:18: cannot find symbol
    [javac] symbol : class WSPasswordCallback
    [javac] location: class org.example.www.esempio.PWCBHandler
    [javac] WSPasswordCallback pwcb = (WSPasswordCallback)callbacks[i];
    [javac] ^
    [javac] D:\Universita\Web Service\esempio\src\org\example\www\esempio\PWCBHandler.java:18: cannot find symbol
    [javac] symbol : class WSPasswordCallback
    [javac] location: class org.example.www.esempio.PWCBHandler
    [javac] WSPasswordCallback pwcb = (WSPasswordCallback)callbacks[i];
    [javac] ^
    [javac] 3 errors

    BUILD FAILED
    D:\Universita\Web Service\esempio\build.xml:43: Compile failed; see the compiler error output for details.

    Total time: 2 seconds

    quale potrebbe essere il problema?

    • Sembra appunto che il package non sia stato importato tra le librerie:
      package org.apache.ws.security does not exist

Leave a reply to kaosktrl Cancel reply