MokaByte Numero 23  -  Ottobre 98

di 
Alessandro Bemporad
CORBA 
Event Service
 
Come un sistema distribuito basato su CORBA utilizza il sistema di gestione degli eventi per scambiare messaggi fra la parte server e quella client

 
 



 
 
 
 
 
Introduzione

OMG, il consorzio di aziende che ha definito lo standard CORBA, ha pubblicato le proprie specifiche in una specie di "bibbia" in due volumi, e su questi due volumi devono basarsi coloro che intendono realizzare una implementazione reale e funzionante dello standard per gli oggetti distribuiti. Due esempi di aziende che hanno avuto il coraggio di avventurarsi in questo cammino irto di pericoli sono Inprise/Borland, che produce Visibroker, e Iona Technologies, con il suo Orbix.  Se osserviamo più da vicino i due tomi, ci accorgiamo che il primo reca il titolo di "CORBA: Architecture and Specification", ed il secondo "CORBAServices, Common Services Specification". Mentre il primo volume contiene la definizione dell'ORB, del linguaggio IDL, del protocollo IIOP, insomma illustra l'architettura del sistema, il secondo contiene una serie di direttive per la costruzione di una serie di "servizi". Un servizio in CORBA è un gruppo di funzioni di cui è stata riconosciuta l'utilità, e di cui è stata decisa la definizione di uno standard in modo da renderne disponibile un implementazione coerente e portabile. 

Uno di questi servizi, quello di cui ci occuperemo in questo articolo, è il cosiddetto Event Service. Il nome suggerisce che abbiamo a che fare con la gestione di "eventi" in CORBA, ed infatti è proprio così. Ma prima di addentrarci nella specifica, cerchiamo di mettere a fuoco quello di cui stiamo parlando. 

Eventi

Quando parliamo del verificarsi di un evento, intendiamo esprimere semplicemente il fatto che in un dato momento, in un certo luogo, è successo qualcosa. Se ad esempio in casa vostra, alle 22.30 in punto di un giovedì il vostro televisore cessa improvvisamente di funzionare mentre stavate guardando il finale di un thriller, in quel momento si è verificato un evento. A questo punto, il giorno dopo sarete costretti a portare il vostro televisore in un centro assistenza autorizzato, e dopo qualche tempo si verificherà un altro evento, ovvero il vostro televisore tornerà a funzionare e voi potrete recarvi al centro assistenza per ritirarlo e riportarlo finalmente a casa. Un altro evento possibile potrebbe riguardare il fatto che il tecnico riparatore utilizzi male il saldatore e comprometta in modo permanente il funzionamento del vostro televisore. Nel seguito dell'articolo, per semplicità, sceglieremo di seguire il primo dei due eventi. Concentriamoci adesso su quattro elementi in particolare: voi, il tecnico riparatore, il centro assistenza, e la riparazione del vostro televisore. E' evidente che voi ed il riparatore di televisori conducete due esistenze totalmente separate, e siete legati solo da un imperscrutabile destino: voi siete interessati ad avere indietro il vostro televisore, ed il riparatore è l'unico capace di darvi questo servizio. Inoltre voi non vedrete mai in faccia il riparatore, ed il riparatore non saprà mai a chi appartiene il televisore. Infatti voi portate il televisore al centro assistenza, ed il centro assistenza consegna il televisore ad uno dei suoi riparatori.  A questo punto, si prefigurano due scenari differenti. Nel primo, voi telefonate tutti i giorni al centro assistenza, sempre più angosciati, chiedendo notizie del vostro televisore, fino a quando vi viene data l'informazione che l'evento tanto atteso si è verificato. Nel secondo scenario, per evitare scocciature, il centro assistenza vi richiede di fornire il vostro numero di telefono, e vi intima di non stare a telefonare, dato che sarà sua cura avvertirvi non appena il riparatore terminerà il proprio lavoro.  Bene, adesso cominciamo ad assegnare dei termini un pò più rigorosi agli elementi dell'odissea del televisore, e vediamo cos'ha a che fare tutto questo con l'Event Service di CORBA. 

Innanzitutto diciamo che la riparazione del vostro televisore è un evento [event], che il riparatore di televisori è un produttore di eventi [event supplier], che voi siete un consumatore di eventi [event consumer] e che il centro assistenza, che fa da tramite tra voi ed il riparatore, è un canale di eventi [event channel], che trasporta l'evento dal supplier al consumer, pur mantenendo i due completamente all'oscuro dell'esistenza l'uno dell'altro.   Adesso torniamo a guardare i due scenari che avevamo prima prefigurato. Nel primo, eravate voi a telefonare (con angoscia crescente ma di vostra iniziativa) al centro assistenza, il quale a sua volta provvedeva a chiedere al riparatore la situazione del vostro televisore. Nel secondo avveniva il contrario, ovvero il riparatore avvertiva il cento assistenza al termine del lavoro, ed a questo punto il centro assistenza provvedeva (con il dovuto ritardo) a telefonarvi.  Diamo per scontato che è sempre un supplier a generare l'evento, ed un consumer a riceverlo, e che la trasmissione dell'evento avviene sempre attraverso un event channel. Nel primo scenario il consumer decide di propria iniziativa di interpellare l'event channel per sapere se l'evento è disponibile, ed a sua volta l'event channel rigira la domanda al supplier. Nel secondo scenario, è il supplier a guidare l'azione, e quando l'evento si verifica provvede a segnalarlo all'event channel, che a sua volta lo innoltra ("spinge") verso il consumer in attesa. 

Questi due modelli di comportamento dei consumer e dei supplier vengono chiamati, rispettivamente, pull model (iniziativa al consumer) e push model (iniziativa al supplier).  Ci credereste se vi dicessi che tutto quello che vi ho raccontato finora è esattamente il funzionamento dell'Event Service CORBA? No? Beh, dovrete ricredervi perchè invece è proprio così, ed ora vedremo infatti come. 

Event Service 

L'Event Service è un meccanismo che consente di realizzare applicazioni distribuite estremamente sofisticate e potenti. L'idea è quella di realizzare un sistema di comunicazione di eventi tra oggetti distribuiti, disaccoppiandoli completamente tramite l'utilizzo di un event channel fornito dall'Event Service stesso.  La comunicazione asincrona e distribuita di eventi, è in qualche modo riproducibile anche tramite il meccanismo delle cosiddette callback, di cui parleremo in un altro articolo, per altro realizzabili in modo distribuito in CORBA. Accenniamo per adesso solamente al fatto che l'implementazione di una callback costringe gli oggetti client e gli oggetti server a "conoscersi" reciprocamente, cosa che in qualche modo ne limita la manutenzione ed il riutilizzo.  Il vantaggio principale dell'Event Service consiste invece nel fatto che i produttori ed i consumatori di eventi sono totalmente disaccoppiati tra loro e quindi manutenibili ed espandibili in modo del tutto indipendente. Aggiungete al quadro anche il fatto che questi oggetti, grazie alla natura distribuita di CORBA, possono risiedere su server diversi in rete locale o geografica, e questo apre le porte a soluzioni applicative di tutto rispetto, altrimenti difficilmente realizzabili. 
 

EventService API - Creazione di Oggetti Consumer e Supplier 

Lo schema di funzionamento dell'Event Service si basa fondamentalmente sull'intersezione tra i concetti di supplier e consumer di eventi, e quelli di push model e pull model. Questo significa che esistono quattro tipi di attori possibili, dei quali andiamo subito a fare la conoscienza: 

  •      Un push supplier è un produttore che immette di propria iniziativa gli eventi in un event channel. 
  •      Un push consumer è un consumatore, che riceve eventi su iniziativa dell'event channel. 
  •      Un pull supplier è un produttore, dal quale l'event channel preleva gli eventi di propria iniziativa. 
  •      Un pull consumer è un consumatore, che richiede di propria iniziativa gli eventi all'event channel. 
Normalmente un push supplier viene associato ad un push consumer, ed un pull supplier ad un pull consumer, ma questo non è realmente necessario, ed è possibile creare anche architetture miste. Inoltre è importante osservare che un event channel può essere condiviso tra un qualunque numero di supplier e di consumer, a patto che siano tutti produttori o consumatori dello stesso evento.  Queste quattro entità sono rappresentate in CORBA IDL da altrettante interface. Una qualunque classe può diventare quindi produttore o consumatore di eventi nel modello push o pull semplicemente implementando l'opportuna interface: 
interface PushSupplier {

  void disconnect_push_supplier();

};

interface PushConsumer {

  void push(in any data) raises (Disconnected);

  void disconnect_push_consumer();

};

interface PullSupplier {

  any pull() raises (Disconnected);

  any try_pull(out boolean has_event) raises (Disconnected);

  void disconnect_pull_supplier();

};

interface PullConsumer {

  void disconnect_pull_consumer();

};

ProxySupplier e ProxyConsumer

Un EventChannel deve fare da intermediario tra i produttori ed i consumatori di eventi per mantenerli disaccoppiati. Per svolgere questo compito, utilizza un meccanismo chiamato proxy. In poche parole, l'EventChannel si presenta ad un produttore di eventi fingendo di essere un potenziale consumatore, e viceversa si presenta ad un consumatore di eventi come un potenziale produttore. Usando i termini corretti, diciamo che un EventChannel si presenta ad un consumer come un ProxySupplier, e si rivolge ad un supplier come un ProxyConsumer.  Dato che i produttori ed i consumatori di eventi devono scegliere se utilizzare il modello push o il modello pull, questo significa che anche i proxy devono supportare entrambi questi modelli, e questo ci porta ad un totale di quattro possibili oggetti proxy nell'EventChannel: 
  • Un ProxyPushSupplier, da fornire ad un oggetto PushConsumer. 
  • Un ProxyPullSupplier, da fornire ad un oggetto PullConsumer. 
  • Un ProxyPushConsumer, da fornire ad un oggetto PushSupplier. 
  • Un ProxyPullConsumer, da fornire ad un oggetto PullSupplier. 
Ciascuno di questi quattro oggetti è rappresentato in CORBA da una classe che porta lo stesso nome, ciascuna delle quali  è sottoclasse delle rispettive classi Consumer e Supplier. Ad esempio, la classe ProxyPushSupplier è sottoclasse di PushSupplier, e così via. 

Connessione all'EventChannel 

Una volta creati gli oggetti supplier e consumer, è necessario "agganciarli" all'event channel, prima di poter iniziare a generare e ricevere eventi. L'event channel non è un concetto mistico, ma semplicemente un oggetto CORBA che implementa l'interface EventChannel, che viene messo a disposizione del programmatore direttamente dall'Event Service.  L'interface dell'EventChannel contiene, tra gli altri, i seguenti due metodi: 
 

interface EventChannel {

  ConsumerAdmin for_consumers();

  SupplierAdmin for_suppliers();

};

Supponiamo adesso di avere un oggetto supplier, ad esempio un PushSupplier, e di volerlo connettere all'event channel. E' necessario a questo scopo seguire un procedimento in tre passi, che andiamo subito ad elencare:  Per prima cosa, chiamiamo il metodo for_suppliers() sull'EventChannel. Questo metodo ci ritorna un oggetto  SupplierAdmin, che è capace di eseguire due sole ma importanti operazioni: 
 

     interface SupplierAdmin {

         ProxyPushConsumer obtain_push_consumer();

         ProxyPullConsumer obtain_pull_consumer();

     };

L'oggetto SupplierAdmin così ottenuto ci consente di accedere al consumer proxy di cui abbiamo bisogno, scegliendo quello giusto in base al modello push o pull selezionato. Chiamiamo quindi senza timore il metodo obtain_push_consumer(), ed otteniamo in ritorno il nostro oggetto ProxyPushConsumer. Diamo un occhiata alla  definizione della sua interface IDL: 
 

       interface ProxyPushConsumer : PushConsumer {

      void connect_push_supplier(in PushSupplier push_supplier);

        };

Adesso possiamo finalmente registrare il nostro oggetto PushSupplier nell'EventChannel, passandolo come parametro del metodo connect_push_supplier() del proxy consumer che gli è stato assegnato.  Ecco fatto, il nostro produttore di eventi è felicemente connesso all'event channel!  Lo stesso procedimento, realizzato con gli stessi tre passi, ma utilizzando metodi speculari a quelli appena visti, viene eseguito da un qualunque oggetto consumer che desidera connettersi all'event channel. 
 

Generazione e ricezione di eventi. 
 

Seguendo il cammino fatto finora, supponiamo adesso di avere un oggetto PushSupplier ed un oggetto PushConsumer connessi all'EventChannel, tramite i rispettivi ProxyPushConsumer e ProxyPushSupplier. Che succede nel momento in cui il supplier genera un evento?  Vi ricordate quando vi ho detto che le classi proxy sono sottoclassi di quelle supplier e consumer? Ebbene, quando il supplier decide che è arrivato il suo momento, chiama il metodo push(in any data) sull'oggetto ProxyPushConsumer, e gli passa come parametro l'evento desiderato. In CORBA, il tipo Any consente di rappresentare qualunque tipo di dato, semplice o complesso che sia, quindi l'evento generato può essere un qualunque tipo di dato o una struttura di dati. Adesso l'evento è passato nell'event channel, il quale guarda se ci sono oggetti consumer registrati.  A sua volta, l'oggetto consumer da noi creato, dovendo come il proxy consumer di prima implementare l'interface PushConsumer, possiede il suo metodo push(), all'interno del quale avremo implementato il codice che deve essere eseguito in risposta all'evento. Cosa succede allora? Succede che l'event channel chiama il metodo push() nel nostro oggetto consumer, e gli consegna come parametro l'evento originario. Il gioco è fatto.  Se avessimo impiegato il metodo pull, anzichè quello push, lo schema sarebbe stato simile ma avrebbe funzionato al contrario. Infatti, in questo caso il nostro oggetto PullConsumer avrebbe chiamato a nostra discrezione il metodo pull(), o try_pull() nel suo ProxyPullSupplier(), per vedere se l'event channel aveva qualche evento da consegnargli. La differenza tra pull() e try_pull() consiste nel fatto che mentre pull() "blocca" per un tempo indefinito il consumer in attesa di un evento, il metodo try_pull() ci consente di eseguire una specie di "polling", e ritorna subito se non ci sono eventi disponibili. A sua volta, l'event channel avrebbe chiamato il metodo pull() nel nostro PullSupplier, mettendosi in ascolto per l'arrivo di nuovi eventi.  Lascio a voi il compito di immaginare cosa può succedere mischiando supplier e consumer che implementano metodi push e pull differenti! 
 

Conclusione

L'Event Service, assieme agli altri servizi e all'architettura stessa dello standard CORBA, ci consente di dare vita ad una nuova generazione di applicazioni, che in assenza di tali specifiche non potrebbero essere nemmeno pensate, e quest'articolo voleva essere solo un assaggio delle potenzialità nascoste nella "bibbia" di OMG. La prossima volta che avrete dei guai con il vostro televisore, assicuratevi di rivolgervi ad un buon centro di assistenza push. Siete avvertiti. 

Bibliografia:
 

  • The Object Management Group - CORBAServices: Common Object Services Specification - 1997
  • D.Pedrick et al. - Programming with VisiBroker - Wiley 1998

 
 
Alessandro Bemporad è un consulente informatico, collabora con Inprise/Borland e Oracle Italia come trainer e project manager,
e si occupa di ambienti di sviluppo Java/CORBA. 

 
 
 


MokaByte Web  1998 - www.mokabyte.it 
MokaByte ricerca nuovi collaboratori. Chi volesse mettersi in contatto con noi può farlo scrivendo a mokainfo@mokabyte.it