MokaByte 96 - Maggio 2005
  MokaByte 96 - Maggio 2005  

 

 

 

La piattaforma J2ME ed i Web Services
II parte: le JSR-172

Nel precedente articolo abbiamo visto come l'utilizzo di protocolli standard come l'HTTP e l'XML permetta di raggiungere quella che viene definita come interoperabilità tra sistemi eterogenei e che hanno portato alla definizione dei Web Service

Da quanto visto è emersa la necessità di una ulteriore serie di standard che permettessero di regolare anche quelli che sono i meccanismi alla base dei Web Service ovvero quelli di:

  • individuazione
  • descrizione
  • invocazione

di un servizio. Si tratta di una serie di standard gestiti da una organizzazione che prende il nome di WS-I (Web Services Interoperability Organization) sotto il controllo della W3C (World Wide Web Consortium) e della OASIS (Organization for the Advancement of Structured Information Standards), e che hanno come scopo principale quello di definire un insieme di regole.
Una prima necessità è quella relativa alla disponibilità di un protocollo di trasporto e codifica delle informazioni attraverso l'utilizzo di XML su HTTP. A tale scopo sono state definite le specifiche SOAP (Simple Object Access Protocol) nella versione 1.1. Per poter invocare un particolare servizio è necessario conoscere la modalità di accesso, quelli che sono i parametri di ingresso e quelli di uscita. Per fare questo lo standard adottato è descritto dalle specifiche WSDL (Web Services Descriptor Language) anch'esse nella versione 1.1. Abbiamo già visto, nel precedente articolo, come un documento WSDL (Web Servce Description Language) permetta di descrivere l'interfaccia di un Web Service e vedremo successivamente come lo stesso potrà essere utilizzato per la generazione del codice da utilizzare per l'accesso al servizio stesso.
Per poter utilizzare un particolare Web Service esistono due diverse modalità che possiamo distiguere in dinamica e statica. Si tratta di un concetto analogo a quello che esiste per CORBA (Common Object Request Broker Architecture) e che dà il significato al termine Common. Come per un servizio CORBA, infatti, esiste la possibilità di invocarlo conoscendone già le caratteristiche oppure di accedervi dopo una fase di ricerca (discovery). Nel primo caso possiamo parlare di invocazione statica, nel secondo di invocazione dinamica. Un servizio che permette quindi di eseguire delle ricerche, secondo diversi criteri, di Web Service si appoggia sullo standard chiamato UDDI (Universal Descripion, Discovery and Integration) nella versione 2.0.
Ovviamente il tutto utilizza in modo spinto quelle che sono le caratteristiche di un documento XML che quindi soddisferà le specifiche XML (eXtensible Markup Language) 1.0 ed un meccanismo di validazione definito dalle specifiche XML Schema.
Come possiamo notare il raggiungimento della tanto sospirata interoperabilità tra sistemi eterogenei può essere raggiunta attraverso l'utilizzo di un numero di tecnologie diverse che difficilmente potranno essere riproposte come sono nel caso di sistemi con risorse limitate come quelli a cui si riferisce la piattaforma J2ME (Java 2 Micro Edition). Anche nel caso delle piattaforme J2SE e J2EE il WS-I ha definito una serie di linee guida che limitano le diverse interpretazioni delle numerose specifiche descritte in precedenza, e che prende il nome di WS-I Basic Profile nella versione 1.0.
Sebbene il mondo Web Service sia abbastanza esteso, si è pensato di applicarlo anche ad un insieme di dispositivi con risorse limitate come quelli idonei all'utilizzo dell'ambiente J2ME, dando origine a quelle che sono le WSA (J2ME Web Services API) descritte dalla JSR-172 . Si tratta di specifiche, basate sul WS-I Basic Profile 1.0, che hanno lo scopo di standardizzare quelle che sono le principali caratteristiche di un client per Web Service:

  • invocazione di funzioni remote
  • parsing XML

Notiamo subito come si tratti di funzionalità caratteristiche di un client; l'utilizzo di un dispositivo cellulare o PDA come server di un servizio Web non sarebbe, almeno con le potenzialità dei sistemi attuali e la limitata connettività, una scelta che trova attualmente molti riscontri.
Le WSA sono quindi pensate per poter essere eseguite sia per Configuration CDC che CDLC sia nella versione 1.0 che nella versione 1.1. Come accaduto per altre API per l'ambiente J2ME, esse sono state ottenute attraverso una selezione di quelle che sono le API analoghe disponibili per J2SE. Per quello che riguarda l'invocazione remota si è pensato di prendere un sottoinsieme delle JAX-RPC 1.1 (Java API for XML-Based Remote Procedure Call) alle quali sono state aggiunte alcune classi di RMI (Remote Method Invocation) dalle quali le prime dipendevano. Per quello che riguarda il parsing XML si è pensato di considerare un sottoinsieme di un parser molto leggero come può essere SAX2 (Simple API for XML Parsing). Di seguito descriveremo quindi le API per invocare dei servizi remoti da dispositivi J2ME e per eseguire il parsing di documenti XML.


Cosa le JSR-172 non fanno
Una delle principali cause di fallimento di progetti basati sulla tecnologia J2ME è sicuramente una trascurata analisi di quelle che sono le funzionalità che il dispositivo mette a disposizione. Spesso ci si aspetta che un dispositivo sia in grado di eseguire operazioni che invece non sono alla sua portata. Un esempio banale è la semplice mancanza del supporto per un particolare Optional Package come potrebbe essere quello per l'invio dei messaggi SMS. Oltre che esaminare quelle che sono le operazioni che un dispositivo è in grado di eseguire è bene valutarne soprattutto le limitazioni. Queste verifiche vanno fatte anche all'interno di uno stesso Optional Package. Un esempio è quello dei formati video o audio supportati dalle MMAPI (Mobile Multimedia API). Non è detto che un dispositivo che le supporta sia in grado di riprodurre un file MP3.
Anche nel caso delle JSR-172 è quindi bene sapere che cosa fanno ma soprattutto che cosa non sono in grado di fare. Abbiamo visto che essere permettono di dotare un dispositivo J2ME delle funzionalità caratteristiche di un client. Un client, prima di accedere ad un particolare servizio, potrebbe avere la necessità di fare una ricerca attraverso il protocollo UDDI. Ebbene, la ricerca di servizi attraverso la tecnologia UDDI non è una funzionalità prevista da un client che utilizzi le WSA. Un client potrebbe, inoltre, non solo accedere ad un servizio ma anche eseguire operazioni di deploy, undeploy o altre operazioni che definiamo di amministrazione. Anche queste operazioni per il momento non sono supportate dalle WSA descritte dalle JSR-172.
Il ruolo delle WSA è quindi quello di permettere, ad un dispositivo J2ME, di poter accedere ed utilizzare un servizio esposto attraverso una interfaccia Web Service. Lo scenario principale è quindi quello che prevede un client J2ME che utilizza un particolare servizio a runtime locale per l'accesso a servizi Web in modo semplice e snello. Analogamente a quanto avviene nel caso J2SE, le WSA ci dovranno mettere a disposizione uno strumento per generare degli stub che, attraverso un servizio locale a runtime, ci permetteranno di accedere ad un Web Service in modo trasparente.

 

Come funzionano le JAX-RPC API delle WSA
L'architettura di un applicazione J2ME che utilizza le WSA prevede la definizione delle seguenti componenti (Figura 1):

  • Applicazione J2ME che intende utilizzare un particolare Web Service
  • Uno stub compliant con le JSR-172
  • Un servizio a runtime a cui lo stub accede attraverso una interfaccia che prende il nome di Service Provider Interface

Sebbene le architetture per applicazioni J2ME non seguano le normali regole di programmazione OO per motivi di spazio, in questo caso si è scelto di utilizzare un livello di astrazione tra quella che è l'interfaccia di accesso ad un servizio locale e la sua implementazione. Il ruolo del Service Provider Interface è appunto quello di astrarre i servizi di gestione della connessione e codifica dei dati dalla effettiva implementazione la quale viene lasciata al particolare vendor.L'implementazione dei servizi descritti dalla Service Provider Interface è quella che prende il nome di runtime.


Figura 1
-Architettura delle WSA

Dalla figura si nota come una particolare applicazione non utilizzi direttamente i servizi della SPI ma vi acceda attraverso quello che si chiama Stub il quale viene generato in modo automatico a partire dal WSDL di un servizio attraverso l'utilizzo di un insieme di tool forniti dal particolare vendor. Le operazioni per poter utilizzare le WSA sono quindi le seguenti:

  1. Generare uno JAX-RPC Stub secondo quelle che sono le specifiche JSR-172a partire dal file WSDL attraverso l'utilizzo del tool fornito dal particolare vendor
  2. Creare una istanza dello stub all'interno dell'applicazione J2ME
  3. Invocare i servizi web attraverso i metodi forniti dallo stub e corrispondnti agli elementi wsdl:operation nel file WSDL che descrive il servizio stesso

La modalità di accesso alle funzionalità di runtime attraverso l'utilizzo di un stub è solo il modo più semplice per accedere ad una Web Service attraverso WSA le quali mettono a disposizione anche API di più basso livello. Come accennato, lo Stub viene generato a partire dal WSDL attraverso un tool che prende il nome di stub generator e che viene fornito con il particolare vendor. Si tratta di un tool che ha in input il file WSDL e genera in output un insieme di classi java che permettono l'accesso al servizio descritto attraverso l'utilizzo degli strumenti di runtime esposti attraverso la SPI. L'utilizzo di un tool di questo tipo è auspicabile in quanto può permettere di partire da una stessa definizione del servizio attraverso interfaccia WSDL, e di generare Stub diversi a seconda delle diverse implmentazioni. Nel caso di implementazioni diverse non sarà quindi necessario programmare a basso livello ma semplicemente utilizzare il tool opportuno per la generazione del codice corrispondente. Quello esposto è lo stesso concetto alla base dell'accesso a servizi attraverso CORBA o RMI (Remote Method Invocation). Nel caso di CORBA, le interfacce si descrivono attraverso un linguaggio che prende il nome di IDL (Interface Description Language). Da una interfaccia descritta in IDL è quindi possibile generare in modo automatico i sorgenti Java, C++ o in altro linguaggio. Analogamente con RMI si definisce una interfaccia Java e si generano i relativi Stub e Skeleton attraverso il tool rmic (RMI Compiler). Lo sviluppatore non si deve quindi preoccupare della creazione degli Stub per l'accesso ad un servizio ma solamente della definizione dell'interfaccia ed, ovviamente, l'implementazione del servizio stesso se non già disponibile.
A questo punto il più è fatto in quanto è sufficiente creare una istanza dello Stub, fornire alcune informazioni di inizializzazione ed utilizzarlo per l'accesso ai diversei servizi.

 

Un esempio
Per fare un esempio di invocazione di un Web Service da dispositivo J2ME utilizziamo lo strumento fornito da Sun ovvero il Wireless Tookit nella versione 2.1. Esso mette a disposizione uno strumento per la generazione automatica delle classi dello Stub per l'accesso ad un Web Service. Serve, ovviamente, anche un servizio da invocare. A tale scopo supponiamo di voler accedere ad uno dei servizi messi a disposizione dal sito http://www.xmethods.net che ne raccoglie di diverse tiplogie. Supponiamo quindi di voler accedere ad un semplice Web Service il cui WSDL è accessibile attraverso l'indirizzo http://www.atomic-x.com/xmlservices/HyperlinkExtractor.asmx?wsdl. Si tratta di un servizio che permette di estrarre i linke da una particolare pagina web. Una cosa importante da notare è come la modalità di accesso ai servizi supportata sia solamente quella in stile document/literal e non rpc/encoded. Il documento WSDL che utilizzeremo sarà quindi il seguente (Listato 1.txt).
Come prima cosa definiamo un progetto con il WTK che chamiamo HiperLinkExtractor (Figura 2) e come classe che descrive la MIDlet la classe di nome it.mokabyte.midp20.ws.HiperLinkExtractor. Notiamo come sia sttao selezionato il checkbox relativo alle JSR-172 per l'accesso ai Web Service da J2ME.
Dobbiamo ora generare le classi relative allo Stub. Per fare questo utilizziamo lo strumento fornito con il WTK a cui accediamo attraverso l'opzione Stub Generator del menu Project.



Figura 2 - Creazione del progetto per le WSA

Otteniamo quindi un semplice tool (Figura 3) che prevede la possibilità di inserire le seguenti informazioni:

  • Path o URL del documento WSDL che descrive il servizio
  • Path di output in cui inserire i sorgenti Java generati dinamicamente
  • Package delle classi ch lo Stub generator andrà a creare in modo dinamico

 


Figura 3
- Stub Generator

L'URL del documento WSDL è quello descritto in precedenza. La directory di output è quella dei sorgenti relativi al progetto MIDP. Il package delle classi che intendiamo generare sarà it.mokabyte.midp20.ws.stub. Lo strumento mette a disposizione la possibilità di scegliere se impostare la CLDC 1.0 o 1.1. Si ricorda che la principale differenza tra le due versioni è il supporto al floating point. È ovvio come questa scelta possa influire sul codice degli Stub generato dinamicamente. Non ci resta che premere ok per creare i sorgenti voluti slezionando il pulsante OK. Notiamo a questo punto la generazione dei sorgenti relativi allo Stub che possiamo quindi utilizzare all'interno della nostra MIDlet.
Se tutto è andato a buon fine, possiamo notare come, nella cartella riservata ai sorgenti della nostra applicazione MIDP, siano stati generati i seguenti file del package it.mokabyte.midp20.ws.stub da noi richiesto:


ArrayOfString.java
ExtractUrl.java
ExtractUrlResponse.java
HyperlinkExtractorSoap.java
HyperlinkExtractorSoap_Stub.java

Non ci resta quindi che creare una semplice MIDlet che utilizza lo stub appena creato per l'accesso al servizio. Notiamo come i servizi messi a disposizione dal servizio descritto dal file WSDL dato siano descritti all'interno dell'interfaccia HyperlinkExtractorSoap. Nel caso particolare essa mette a disposizione il metodo
public ArrayOfString extractUrl(String aUrl)
dove ArayOfString è un altro tipo generato in modo automatico che rappresentaun array di String. Per semplificare il tutto supponiamo che la nostra MIDlet, descritta dalla classe HiperLinkExtractorMIDlet (Listato2), non utilizzi alcuna interfaccia grafica ma visualizzi i risultati dell'invocazione su console. Notiamo come i passi da eseguire siano i seguenti:

  1. Creazione di una istanza dello Stub

    serviceStub = new HyperlinkExtractorSoap_Stub();

  2. Impostazione delle proprietà relative allo stub

    serviceStub._setProperty(Stub.ENDPOINT_ADDRESS_PROPERTY, SERVICE_URL);
    serviceStub._setProperty(Stub.SESSION_MAINTAIN_PROPERTY, new Boolean(true));

  3. Accesso al servizio

    ArrayOfString returnArray = serviceStub.extractUrl(INPUT_PARAMETER);

a cui seguirà l'elaborazione del risultato in relazione a quello che è il tipo di ritorno del servizio. Attraverso questo semplice esempio abbiamo quindi visto come sia stato semplice, attraverso l'utilizzo di opportuni tool, e nel rispetto delle diverse limitazioni dello strumento, accedere a Web Service da dispositivi J2ME conoscendo solamente il docuemnto WSDL di descrizione del servizio stesso.

 

Le JAXP su J2ME per il parsing di documenti XML
Oltre agli strumenti per l'invocazione di Wervizi Web, le WSA possono fornire le API per il parsing di documenti XML. È bene infatti ricordare che le due API possono essere fornite in modo indipendente l'una dall'altra. Le API per il parsing di documenti XML previste dalle WSA sono un sottoinsieme molto ridotto delle SAX nella versione 2.0 (non più compatibile con la 1.0) ma ne mantengono comunque le principali funzionalità che possiamo elencare in:

  • Supporti ai namespace
  • Supporto alle codifiche UTF-8 ed UTF-16
  • Supporto allo standard SAX 2.0 ma non allo standard DOM considerato troppo pesante
  • Non prevede il supporto allo standard XSLT (eXtensible Stylesheet Language Transformations)
  • Supporta le DTD (Data Type Definition)

Quest'ultima caratteristica riguarda la capacità del parsing di validazione dei diversi documenti considerata ora una operazione facoltativa in quanto molto dispendiosa.
La modalità di utilizzo di un parser di questo tipo è analoga a quanto avviene per le JAXP che si utilizzano nel caso J2SE. Anche in questo caso le operazioni da eseguire sono le seguenti:

  • Si estende la classe DefaultHandler per creare una realizzazione della classe responsabile della gestione degli eventi di notifica caratteristici di un parser SAX
  • Si ottiene, attraverso un SAXParserFactory, il riferimento alla particolare implementazione di parser SAX messo a disposizione dall'implementazione delle WSA
  • Si ottiene un riferimento ad uno stream per l'accesso al documento da parserizzare
  • Si esegue l'operazione di parsing del documento con l'handler creato in precedenza

Creare un Handler consiste, come detto, nell'estensione della classe DefaultHandler e nell'overriding dei metodi di callback tra cui :

  • startDocument
  • startElement
  • characters
  • endElement
  • endDocument

ed altri.

 

Conclusioni
In questo articolo abbiamo dato una panoramica di quelli che sono gli strumenti per l'accesso a Web Service e parsing di documenti XML in applicazioni J2ME. Abbiamo visto quelle che sono le funzionalità possibili e le relative limitazioni.

Risorse
I sorgenti del progetto WTK dell'esempio