Axis2 e la gestione dei soap header

Come avete potuto notare attualmente sono focalizzato sui web services, in particolar modo sto lavorando con Axis2 che funziona non solo come container ma mette a disposizione strumenti per lo sviluppo come wsdl2java. Andiamo per ordine.

Un servizio web, come qualcuno di voi sa, non è altro che una serie di operazioni compiute da una applicazione (in questo caso scritta in java) che è raggiunta via web. In particolar modo queste operazioni si scambiano per lo più messaggi SOAP.

Questi messaggi SOAP sono sostanzialmente messaggi scritti in XML che viaggiano su protocollo HTTP e sono strutturati in un header e in un body.

La descrizione di questi messaggi, legati alle operazioni di cui fanno parte, è fatta dai file WSDL che appunto descrivono il web service. Talvolta, anzi spesso, questi file WSDL sono accompagnati da XML schema (file con estensione xsd) che descrivono la struttura degli elementi dei messaggi.

Molte volte avrete necessità di inserire questi elementi nel body ma puo’ capitare di voler metterli nell’header. Per far cio’ dovete specificare l’header come elemento soap:header all’interno della soap:operation (scusate se entro nel dettaglio, comunque potete vedere le specifiche WSDL)

Axis2 fornisce strumenti automatici che partono dal file WSDL e creano delle classi java, chiamate stub e skeleton, a cui si appoggieranno i vostri client e server (lo strumento è chiamato WSDL2Java ed puo’ essere incluso come plugin in Eclipse e in Netbeans) . Al momento della creazione avrete necessita’ di decidere quale parser utilizzare di solito a scelta tra ADB, Xmlbeans, Jibx. Questi parser trasformano gli elementi XML dichiarati nel file WSDL in oggetti java.

Se avete mai realizzato un web service con gli strumenti di Axis2 avrete notato, facendo anche la più semplice operazione, che normalmente gli elementi vengono incapsulati nel body. Ma se aggiungete un elemento header come accennato sopra cosa accade ?

Ebbene occorre purtroppo dire che lo stub permette di richiamare il servizio passando l’elemento che vogliamo aggiungere nell’header senza nessun problema mentre cio’ non accade con lo skeleton. In particolare lo skeleton viene richiamato da un’altra classe che è automaticamente generata ed il cui nome finisce in genere per MessageReceiverInOut. Questa classe ha un metodo che si chiama invokeBusinessLogic, essa recupera il messaggio in ricezione e invia il messaggio in uscita dal web service una volta richiamato lo skeleton.

Dovete sapere che Axis2 ha diversi stati o sessioni cioè strutture dati (classi java) che memorizzano, in breve, lo stato delle operazioni e dei messaggi. Ogni messaggio, in particolare è incapsulato nella classe MessageContext la quale sta a livello inferiore dell’OperationContext che è la classe che rappresenta lo stato della operazione. Ci sono stati di livello superiore per avere un dettaglio vederei riferimenti a fondo pagina.

Di conseguenza il metodo invokeBusinessLogic prende un MessageContext ingresso e restituisce un nuovo MessageContext in uscita. Succede pero’ che il metodo che dovrete implementare nello skeleton  restituisce solo un oggetto che viene messo in un messaggio SOAP creato sull’istante dal metodo invokeBusinessLogic.

Quindi a nulla vale aver creato nello skeleton il soap envelope (messaggio SOAP) con tanto di header perchè appunto nel metodo invokeBusinessLogic viene creato un nuovo messaggio SOAP (in cui andrà il risultato del metodo dello skeleton) non curandosi del messaggio creato nello skeleton.

Allo stato attuale quindi o dovete modificare a mano la classe MessageReceiverInOut oppure dovete pensare a soluzioni come quella di includere un header dentro al body. Dovete pensare che le classi generate non sono intoccabiliti semplicemente assistono chi vuole creare un servizio web quindi se volete modificatele pure.

Questo problema è stato verificato con Axi2 1.3 e Axis2 1.4 e con i parser ADB e Xmlbeans.

Riferimenti:

Advertisements

9 thoughts on “Axis2 e la gestione dei soap header

  1. Forse non sono perfettamente a tema, ma ti espongo il mio problema.
    Prima tramite axis interrogavo web services, e scrivevo in file xml i messaggi soap della request e della response.
    Uitizzavo istruzioni del tipo:

    Call call = binding._getCall();
    MessageContext ctx = call.getMessageContext();
    Message richiesta = ctx.getRequestMessage();
    Message risposta = ctx.getResponseMessage();

    ottenendo le informazioni che il client e il web service si scambiano nella request e nella response con i metodi:

    richiesta.getSOAPPartAsString()
    risposta.getSOAPPartAsString()

    Con Axis2 non riesco a fare qualcosa di analogo. Hai dei suggerimenti e delle indicazioni per realizzare anche con Axis2 quello che prima realizzavo con Axis?

  2. Ciao,

    scusa per il ritardo, ero in ferie, non so se la mia risposta è ancora utile ma almeno ci provo.

    Con questa riga:
    this.inMessageContext=MessageContext.getCurrentMessageContext();

    recuperi il MessageContext e poi su di esso recuperi l’envelope con il metodo getSoapEnvelope().

    Dal MessageContext poi anche risalire al livello superiore.

    E’ nello skeleton che devi poi implementare il metodo come al solito, mentre dovresti avere altre 2 classi MessageReceiverInout (se è un webservice ingresso-uscita) e CallbackHandler in caso di comunicazione asincrona

  3. Ti ringrazio per la risposta, sebbene almeno per come l’ho interpretata non mi è stata utile.
    Andando nelle API di Axis2, ho verificaro che non esiste il metodo getCurrentMessageContext() che tu mi suggerisci di usare (metodo che invece esiste in Axis).
    C’è invece il metodo getEnvelope(), che restituisce la seguente classe SOAPEnvelope di Axiom.
    Andando nelle API di Axiom, vedo che la classe SOAPEnvelope ha vari metodi, ma non mi è chiaro se fanno al caso mio.

    In Axis usando i metodi: getSOAPPartAsString() ottenevo in un passaggio una stringa costituita dai vari tag xml.
    Tale stringa poi la inserivo in un file .xml ed ero apposto: avevo così dei file xml che riprotavano i dati scambiati tra il client e il web services.
    Se in Axis2 ci fossero dei metodi analoghi a getSOAPPartAsString() (ma quali esattamente?) avrei risolto il problema.

    Tieni presente che Axis2 non lo conosco quasi per niente (la documentazione è principalmente in inglese, e non ho trovato nulla di utile), e che mi è stato richiesto di non modificare i ifle generati da Axis2. Pertanto se devo proprio modificare lo skeleton, creerò una classe che lo eredita e cambierò quella.

    Non so se sono stato chiaro su ciò che desidero ottenere.
    Se hai tempo, prova a dare un occhiata al problema, e se trovi qualche soluzione fammela sapere.

    Grazie per la disponibilità.

  4. Ti espongo la mia situazione attuale, nel caso tu possa darmi altri suggerimenti.

    Nelle classi prodotte da Axis2, non ho il Callback, perchè uso una chiamata sincrona.

    Nelle classi prodotte da Axis2, ho lo skeleton.
    Nello skeleton c’è un metodo dedicato al servizio che sto interrogando.
    Questo metodo si limita a lanciare un’eccezione.

    Nelle classi prodotte da Axis2 ho anche il ReceiverInOut.
    Nel receverInOut c’è il metodo invokeBusinessLogic().
    Il metodo invokeBusinessLogic(), quando gestisce il servizio che sto interrogando, tra le altre cose realizza istanzia il metodo dello skeleton che gestisce il servizio interrogato, e assegna l’envelope tramite factory.getDefaultEnvelope();

    Dalle cose che ho capito, io dovrei andare nello skeleton, prendere il MessageContext(), e mettere in esso l’envelope (metodo setEnvelope()). Ma come si fa?

    A quel punto per impedire che tale envelope non venga cancellato da quello prodotto nel ReceiverInOut, dovrei in qualche modo impedire la seguente istruzione

    envelope = factory.getDefaultEnvelope();

    ma con che istruzioni dovrei sostituirla?

    Superato anche questo punto, per recuperare l’envelope dallo stub, che istruzioni dovrei utilizzare ?

    Potrebbe esserti utile guardare anche un post in inglese che tratta un argomento affine, all’indirizzo:

    http://www.mail-archive.com/axis-user@ws.apache.org/msg27540.html

    Non so però se fa al mio caso, e comunque (oltre a chimare metodi che non mi sono ben chiari da dove prende) non dice come agire all’interno del metodo invokeBusinessLogic() per prendere l’envelope settato dallo skeleton.

    Forse sto facendo confusione. Se hai suggerimenti sono ben accetti, altrimenti sarò costretto a rinunciare.

  5. Ciao. È passata acqua sotto i ponti, ma mi pare che le cose non siano cambiate più di tanto in Axis 1.7.4. Sto per seguire la strada che hai descritto in fondo al tuo articolo, perché non ho visto cambiamenti notevoli nell’ambiente.
    Fra parentesi, Axis lo sto usando perché è richiesto dall’architettura, ma se potessi scegliere, credo che avrei seguito la strada più standard.

    • Ciao cosmic53, ti do ragione, nel senso che userei Apache CXF semplicemente perchè si è standardizzato anche se lo stesso Axis usa jaxb, tuttavia i suoi rilasci sono sempre più lenti semplicemente perchè gli autori sono quelli di WSO2 che si concentrano su diversi prodotti.

    • Non credo che sia giusto che Axis sia richiesto dall’archiettura, più che altro gli standard dietro dovrebbero essere richiesti

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s