JAXB and the root element

Recently I helped a friend to implement the client of a web service using Axis2 and Tomcat, developing the client first and the jsp after. After testing the web service with SoapUI we started to develop the client with Eclipse.

The problem with this web service is that the body of the method is an entire xml string contained in a CDATA element, not only for for the request but also for the answer, of course this creates problem to generate the java objects from the wsdl file since the element is not defined as XML.

Luckily we received the xsd files so we generated the java classes with JAXB data binding which is implemented, and it can be executed, through the application xjc that you can find inside the bin folder of the Java Virtual Machine. Note that JAXB is the default databinding of Apache Cxf.

JAXB worked nicely but we had the problem to extract from the xml string the node container which needed to be declared as root element, in other words you need to use the @XMLRootElement annotation otherwise you can have the exception:

unexpected element (…) , Expected elements are (none).

when you unmarshal (from string to java object) the element.

 

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