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:
-
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
- Creare
una istanza dello stub all'interno dell'applicazione
J2ME
- 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:
-
Creazione di una istanza dello Stub
serviceStub = new HyperlinkExtractorSoap_Stub();
- Impostazione
delle proprietà relative allo stub
serviceStub._setProperty(Stub.ENDPOINT_ADDRESS_PROPERTY,
SERVICE_URL);
serviceStub._setProperty(Stub.SESSION_MAINTAIN_PROPERTY,
new Boolean(true));
- 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
|