MokaByte 47 - Dicembre 2000
Foto dell'autore non disponibile
di
Raffaele Spazzoli
I protocolli Discovery 
e Join di Jini
Vai alla prima pagina di questo mese
In questo articolo sono descritti i protocolli di discovery e join necessari ai servizi cooperare con l’ambiente Jini. Vengono inoltre illustrate le modalità di ricerca dei servizi, modalità che consentono ai client di trovare il servizio più rispondente alle loro necessità

Benvenuti alla quarta ed ultima puntata della serie sulle tecnologie di Jini. In questo articolo parleremo dei protocolli di discovery e join. Come in tutti gli ambienti di computazione distribuita il meccanismo per trovare i servizi di cui si ha bisogno rappresenta un elemento fondamentale ed irrinunciabile. La modalità con cui in Jini si cercano i servizi è piuttosto diversa dal modo in cui in RMI o in CORBA si individuano oggetti remoti. In questi due ambienti, infatti, gli oggetti che si vogliono rendere visibili si registrano presso un servizio di nomi fornendo un nome che li individua in maniera univoca. Il database dei servizi disponibili in un djinn (si dice djinn un insieme di servizi Jini logicamente correlati e spesso anche fisicamente contenuti dentro la medesima intranet) è concepito per consentire la ricerca di un servizio non in base ad un nome che il client (colui che richiede il servizio) deve già conoscere, ma in base ai bisogni che tale client si trova ad affrontare. Ad esempio supponendo che il client abbia bisogno di stampare un documento in formato PostScript, allora per prima cosa cercherà nel djinn i servizi in grado di stampare, e fra questi ne sceglierà uno in grado di interpretare il formato PostScript. Il database dei servizi presenti in un djinn è distribuito in un insieme di servizi Jini detti dei lookup service. Non esiste fra lookup service alcun tipo di relazione gerarchica, al contrario di quanto accada per esempio per il servizio di nomi di internet. Il numero dei lookup service presenti in un djinn deve essere deciso dal djinn administrator raggiungendo un compromesso fra availability del servizio di registrazione e performance del djinn. Un servizio Jini quando attivato ha la libertà di registrarsi presso uno, diversi o tutti i lookup service di un djinn, analogamente un client può cercare un servizio presso uno o più lookup service. Questa fluidità e la mancanza di punti di centralizzazione rende Jini particolarmente adatto a sistemi molto dinamici in cui i servizi vengono attivati e disattivati di frequente e in cui anche la topologia della rete possa variare. Naturalmente bisogna pagare un prezzo per questa flessibilità: come vedremo spesso il protocollo Jini fa uso di comunicazioni multicast decisamente adatte a reti locali (Intranet), ma svantaggiose o addirittura non utilizzabili in Internet. I servizi di un djinn sono suddivisi in gruppi; i nomi dei gruppi sono semplici stringhe destrutturate anche se le specifiche della Sun consigliano di assegnare nomi tipo DNS (es. “eng.sun.com”).
Dato un oggetto, sia esso un client o un servizio, affinché possa interagire col djinn è necessario che ottenga uno o più riferimenti ai lookup service; ciò è possibile grazie al protocollo di discovery.
Un servizio una volta ottenuto un riferimento ad un lookup service può unirsi al djinn. Questo però comporta delle responsabilità da parte del servizio che sono descritte nel protocollo di join.
Proprio questa fase è quella cho forse distingue maggiormente Jini dagli altri protocolli di computazione distribuita infatti a questo punto il servizio Jini come parte della registrazione consegna ai lokkup sercice che compongono il djinn un proxy di sé stesso. Questo proxy verrà successivamente consegnato dai lookup service ai client che ne fanno richiesta. I client dovranno usare questo proxy per interagire col servizio Jini.
La caratteristica di Jini che consente di iniettare una classe proxy nel codice del client è quella che rende adatto Jini ad avere come servizi network appliances (cioè elettrodomestici in grado di collegarsi alla rete). Infatti, i costruttori di network appliances difficilmente possono permettersi di installare sui loro prodotti sistemi operativi quali Windows CE o delle JVM a causa della limitata disponibilità di memoria che caratterizza questi apparecchi. E’ molto più probabile che questi device abbiano cablata internamente la logica di funzionamento e siano in grado di comunicare mediante un protocollo proprietario. Il ruolo del proxy diventa quello di driver remoto del servizio. Il proxy è l’unico a conoscere il protocollo di comunicazione del servizio che rappresenta e al momento della registrazione sul lookup service deve essere inizializzato in modo da sapere ritrovare il proprio servizio quando sarà attivato sul lato client. Se il protocollo di comunicazione fra proxy e servizio dovesse essere RMI allora il proxy sarebbe lo stub del server RMI. Questo caso però non è da considerarsi la norma in ambiente Jini contrariamente a quanto affermato alcune voci che erroneamente asseriscono che Jini sia costruito sul protocollo RMI.
 
 
 

Il protocollo di discovery
Il protocollo di discovery consente di trovare i lookup service presenti in un djinn. Non scenderemo nel dettaglio del protocollo (si veda [1]) perché fortunatamente la Sun ci fornisce due classi (LookupDiscovery e LookupLocator) che ne nascondono completamente l’implementazione.
Il protocollo di discovery si compone in realtà di tre sottoprotocolli ognuno dei quali va usato in particolari situazioni. In tutti e tre i casi quando una discovery entity (oggetto in cerca di un lookup service) scopre un lookup service esso risponde mandando un riferimento a sé stesso. Il riferimento è un proxy in grado di comunicare con suo lookup service. Tale proxy deve essere una classe java che espone l’interfaccia ServiceRegistrar. 
Il primo sottoprotocollo si chiama Multicast Request Protocol. Esso deve essere usato quando una discovery entity si attiva e comincia la sua ricerca. Semplificando il Multicast Request Protocol (per maggiori dettagli si veda [1]) prevede che la discovery entity mandi un multicast UDP datagram ad una well-known-port. A questo punto tutti i lookup service in ascolto rispondono attivando un collegamento TCP con la discovery entity. Questo protocollo deve essere usato per scoprire lookup appartenenti ad una Intranet.
Per monitorare l’evoluzione dello stato del djinn una discovery entity deve anche gestire il Multicast Announcement Protocol. Secondo questo protocollo quando un lookup service si attiva comincia a mandare ad intervalli regolari un multicast UDP datagram ad una well-known-port che annuncia la propria esistenza. Qualunque discovery entity che per qualche motivo non fosse a conoscenza di tale lookup service, ricevendone l’annuncio può contattarlo e riceverne il riferimento. Anche questo protocollo usando il multicast UDP è limitato ad una intranet.
L’implementazione di questi due protocolli è incapsulata nella classe LookupDiscovery. Una volta costruito un oggetto di tale tipo esso attiva una serie di thread necessari a gestire i protocolli e notifica i nuovi lookup service tramite DiscoveryEvent che devono essere ricevuti da un DiscoveryListener.
Nel caso una discovery entity si voglia connettere ad un particolare lookup service essa dispone del Unicast Discovery Protocol. Per usare tale protocollo la discovery entity deve conoscere la locazione del lookup service, a questo punto l’Unicast Discovery Protocol prevede che la discovery entity si connetta al lookup service usando una connessione TCP e ne riceva il riferimento.
Poiché il protocollo di trasporto usato in questo caso è TCP Unicast Discovery Protocol può essere usato per scoprire lookup service “lontani”, dispersi in Internet.
Tale protocollo è incapsulato nella classe LookupLocator che riceve come costruttore URL e restituisce un lookup service mediante il metodo getRegistrar().
 
 
 

Il protocollo di join
Quando un servizio ha ottenuto un riferimento ad un lookup service può registrarsi. La registrazione è gestita tramite lease ed è responsabilità del servizio mantenere questi lease “vivi”. Nella fase di registrazione un servizio passa sostanzialmente tre informazioni: un proxy che rappresenterà il servizio sul lato client, un serie di attributi del servizio e l’ID del servizio.
Gli attributi che descrivono il servizio sono raggruppati logicamente in Entry. Le Entry aiutano i client nella ricerca del servizio più adatto alle loro esigenze e inoltre servono a descrivere lo stato del servizio. Per esempio una Entry di un forno a microonde Jini enabled potrebbe monitorare lo stato di cottura del suo contenuto, mentre un'altra potrebbe semplicemente riportare la marca del costruttore.
Affinché un servizio sia un buon servizio nella comunità djinn è necessario che si comporti secondo il Join Protocol. Molto semplicemente secondo il Join Protocol (per maggiori dettagli si veda [1]) un servizio deve mantenere traccia di alcuni dati durante le ripartenze o i crash che possono occorrere. I dati che un servizio Jini deve conservare e che quindi vanno ad aggiungersi alla parte persistente del servizio sono l’ID del servizio, l’insieme delle entry che lo caratterizzano, l’insieme dei gruppi presso cui si deve registrare, l’insieme di particolari lookup service presso cui registrarsi (l’individuazione di questi lookup service deve avvenire con l'Unicast Discovery Protocol).Tali dati devono essere usati alle ripartenze del servizio per ripristinare lo stato delle registrazioni presso i lookup service. 
La Sun ci fornisce una classe che espleta la maggior parte dei compiti prescritti dal Join Protocol. La classe si chiama JoinManager ed accetta nel costruttore i dati di cui sopra. Unica preoccupazione di chi scrive il servizio (Ammesso che abbia a disposizione una JVM su cui possa girare la classe JoinManager) diventa dunque salvare tali dati in memoria stabile in modo da poterne disporre al momento della ripartenza.
 
 
 

Le Entry
Le Entry come detto rappresentano gli attributi e lo stato del servizio. Al momento della registrazione un servizio passa un array di Entry come argomento. In seguito può aggiungere ulteriori entry al proprio stato o modificare il valore di quelle esistenti. Queste variazione devono essere notificate a tutti i lookup service presso cui il servizio è registrato (ci pensa il JoinManager); in seguito con il meccanismo degli eventi remoti tali variazioni vengono notificate ai vari client che abbiano dichiarato interesse per quel servizio.
Una qualunque classe Java può essere una entry purché estenda l’interfaccia Entry e abbia solo membri pubblici.
Le entry si dividono in due tipi, quelle manipolate dal servizio e quelle manipolate dall’esterno. L’idea è che alcune entry quali ad esempio quelle che descrivono lo stato interno del servizio possono essere manipolate solo dal servizio stesso (queste implementano l’interfaccia ServiceControlled). Le altre possono essere impostate da operatori esterni. Ad esempio nel caso di una stampante Jini il produttore del servizio è certamente una entry di tipo ServiceControlled, mentre l’ufficio dove essa si trova deve essere impostato dall’esterno.
La Sun definisce un insieme di entry che ogni servizio dovrebbe avere per essere più semplicemente gestito (si veda [2]); fra queste vi sono il nome lo stato la locazione fisica e altre.
Data la varietà di tipi di entry diventa difficile costruire strumenti di gestione del djinn usabili dall’uomo. Infatti un ipotetico browser di servizi all’interno di un djinn dovrebbe essere un grado di rappresentare propriamente i valori delle entry e consentire la modifica di quelle non ServiceControlled. A tal fine le specifiche [9] suggeriscono che i campi di una entry estendano la classe java.awt.Component (questo consentirebbe loro di essere rappresentati in una interfaccia grafica)o quanto meno presentino un metodo toString() non triviale.
Un altro modo che le entry hanno per essere rappresentati in strumenti browsing e di amministrazione è quello di avere un bean associato. Data una entry di nome xxx la classe bean ad essa associata deve chiamarsi xxxBean ed implementare l’interfaccia EntryBean. L’interfaccia EntryBean presenta il metodo makeLink() che deve servire a collegare una entry al proprio bean in modo tale che le operazioni svolte sul bean si riflettano sulla entry e quindi indirettamente sul servizio. Uno strumento di browsing, ottenuta entry, dovrebbe dunque verificare se essa possiede la corrispondente classe bean; in caso affermativo istanziare un oggetto di tale classe ed associarlo alla entry. A questo punto il problema di rappresentare e modificare i valori di una entry si riconduce al problema di gestire un bean, cosa già affrontata e risolta dalla maggior parte degli ambienti di sviluppo per Java.
 
 
 

Il lookup: la ricerca del servizio giusto
Il client di un djinn una volta ottenuto un riferimento ad un lookup service può cominciare a cercare un servizio che risponda ai suoi bisogni. La ricerca avviene costruendo un modello di servizio (una classe ServiceTemplate) che il lookup service userà per scoprire se ci sono servizi all’interno del djinn che fanno match con esso.
La classe ServiceTemplate prende come costruttore un ID di servizio (ServiceID che può anche essere null), un array di classi (Class) ed un array di Entry. Un ServiceTemplate fa match con un servizio se 

  • I ServiceID corrispondono o se quello del template è null
  • La classe del servizio è una istanza di tutte le classi contenute nell’array di classi.
  • Tutte le entry dell’array di entry trovano almeno una entry con cui fare match fra quelle del servizio.


Due entry fanno match fra loro se:

  • Sono una subclass dell’altra
  • Tutti i campi che hanno in comune sono uguali


Inoltre se una entry contiene dei campi null questi sono considerati wildcard, cioè fanno match con qualunque valore abbia il campo corrispondente della entry che si va a confrontare.
Un client può fare una ricerca di un servizio accontetandosi del primo che rispetta i criteri del ServiceTemplate, in alternativa può farsi restituire tutti i servizi del djinn che rispondono a tali criteri e su questi eseguire ricerche più raffinate.
Inoltre un client può chiedere ad un lookup service di notificarlo tramite un evento del cambiamento del numero di match su un dato ServiceTemplate. Tale opportunità consente al client per esempio di essere notificato quando nel djinn entra un servizio che risponde a particolari caratteristiche.
Una volta ottenuto il proxy di un servizio il client lo può usare come una normale classe Java.
 
 
 

Conclusioni
Con questo articolo si conclude la nostro breve panoramica sulle tecnologie unate in Jini. Ora dovrebbero essere più chiare le potenzialità e i meccanismi interni di funzionamento di questo modello di computazione distribuita. Un problema che è stato sollevato è la necessità di avere interfacce standard per servizi equivalenti in modo da evitare il proliferare di interfacce generate dai produttori di servizi Jini enabled. A tal fine sono già all’opera alcune commissioni ( il cui lavoro può essere visto al sito www.jini.org) per definire interfacce a servizi di stampa e di file server. La cosa che trovo molto stimolante è la possibilità, una volta stabilizzata la fase di standardizzazione delle interfacce, di costruire meta-servizi col compito di amministrare i servizi di più basso livello. Così potremmo avere ad esempio un servizio print manager che al guastarsi di una stampante la esclude dal sistema e ne attiva una seconda di backup, in maniera trasparente ai programmi che devono stampare, ma avvisando l’utente di andare a ritirare le stampe in una nuova locazione. Secondo le voci che si leggono in Internet i primi mesi del nuovo millennio vedranno l’ingresso nel mercato dei primi apparecchi Jini enabled di largo consumo. Sarà appassionante vedere l’evoluzione di questa tecnologia. 
 
 
 

Bibliografia
[1] "Jini Tecnhology Core Platform Specification", Sun Microsystems, 2000
[2] "Jini API Documentation ", Sun Microsystems, 2000
[3] " A Collection of Jini™ Technology Helper Utilities and Services Specifications", Sun Microsystems, 2000

Tutti i documenti sono scaricabili gratuitamente al sito http://www.sun.com/products/jini.

Raffaele Spazzoli è laureato in ingegneria informatica. Da anni coltiva la propria passione per Java studiando e testando le soluzioni tecnologiche introdotte dalla Sun. Può essere contattato tramite e-mail all’indirizzo rspazzoli@mokabyte.it

Vai alla Home Page di MokaByte
Vai alla prima pagina di questo mese


MokaByte®  è un marchio registrato da MokaByte s.r.l.
Java® è un marchio registrato da Sun Microsystems; tutti i diritti riservati
E' vietata la riproduzione anche parziale
Per comunicazioni inviare una mail a
mokainfo@mokabyte.it