MokaByte 70- Gennaio 2003 
RMI over IIOP
di
Giovanni Puliti
RMI, il modello di programmazione distribuita principe di Java, ha come caratteristica principale quella della semplicità. CORBA invece, pur essendo più complesso, garantisce una maggiore interoperabilità. Con RMI-IIOP, il protocollo rilasciato da Sun e IBM nel 1999, è possibile unire CORBA e RMI senza dover imparare nuove tecniche di programmazione o stravolgere il codice Java pensato per RMI.

Introduzione
Remote Method Invocation è il modello di programmazione distribuita di Java introdotto con il JDK 1.1: grazie alla organizzazione basata sulla suddivisione in stub-skeleton, i metodi di un oggetto remoto possono essere invocati da un client remoto senza che questo abbia la percezione che l'oggetto sia invece eseguito utilizzando le risorse del server remoto.
Rispetto all'analogo CORBA, RMI ha il vantaggio principale della semplicità, ma vincola a dover utilizzare strato client e server in Java, ad utilizzare sempre il medesimo protocollo di comunicazione JRMP, rispettando al contempo le modalità di interrogazione dei metodi e di marshalling dei parametri. Per questo motivo RMI offre semplicità ma non è in grado di mantenere interoperabilità con piattaforme differenti ovvero con applicazioni distribuite scritte in linguaggi diversi.
L'altro soggetto principale coinvolto in questo scenario è CORBA, il quale ha una connotazione completamente opposta rispetto a RMI: maggiore interoperabilità pagata al prezzo di una maggiore complessità. Con CORBA una applicazione client Java può interagire con una serie di oggetti remoti scritti in altri linguaggi (C++, Delphi o altri per i quali sia disponibile un mapping IDL) e viceversa.
Dato che Java è diventato il dominatore incontrastato in ambito enterprise soprattutto nella realizzazione di applicazioni distribuite, portabili, ed integrate, si è fatta pressante la necessità di una qualche forma di integrazione fra le due tecnologie.
Era però necessario che tale integrazione fosse realizzata a patto di non alterare le due tecnologie, specialmente la prima: l'introduzione di un ulteriore modello aggiuntivo o un aumento del livello di complessità in RMI avrebbe significato limitare l'arma vincente di Java RMI, ovvero semplicità.
Fortunatamente le modifiche sono state effettuate in gran parte all'interno di CORBA, grazie all'introduzione di alcuni nuovi paradigmi (object by value ed IDL-to-Java) garantendo al contempo sia la retro-compatibilità che l'integrazione con RMI.
Per il lettore nuovo a queste tecnologie, si raccomanda di approfondire sia RMI che CORBA, per poter comprendere pregi e difetti di entrambe e valutare quando si debba preferire l'una all'altra. Dato che tali argomentazioni esulano dallo scopo di questo articolo, si rimanda alla bibliografia riportata al fondo.

 

L'unione dei due mondi
L'integrazione del mondo Java RMI e di CORBA è resa possibile grazie alla introduzione di RMI-IIOP dove IIOP indica Internet Inter Orb Protocol. Si tratta di un protocollo pensato in modo da garantire la comunicazione sullo strato TCP (Internet) e di connettere ORB differenti fra loro (IOP).
Sviluppato congiuntamente da IBM e SUN nel 1999, esso rappresenta il matrimonio fra RMI e CORBA. Lo scenario che si presentava prima della introduzione di RMI-IIOP era quello raffigurato in figura 1: applicazioni distribuite sviluppate in Java RMI e basate sul protocollo JRMP (Java Remote Protocol), non erano in grado di interagire con applicazioni scritte con tecnologie differenti e viceversa.


Figura 1 -
lo scenario delle applicazioni distribuite prima di RMI-IIOP

L'introduzione di RMI-IIOP ha pesantemente modificato le cose, permettendo l'interoperabilità fra i due mondi. Se si osserva la figura 2, si potrà notare come tale tecnologia consenta la comunicazione fra applicazioni solo Java RMI e RMI-IIOP e fra RMI-IIOP e CORBA. Di fatto non è ancora possibile connettere direttamente una applicazione Java RMI direttamente con una CORBA, ma questo nella maggior parte dei casi non è un problema, come avremo modo di vedere.


Figura 2
- RMI-IIOP unisce i due strati applicativi

Ogni linea diretta nella figura rappresenta la possibilità di un client di invocare un oggetto remoto in esecuzione sul server.
Anche se può apparire piuttosto misterioso come ciò sia possibile, in realtà è dovuto ad una situazione molto semplice. Il protocollo RMI-IIOP infatti è in grado di supportare in modo trasparente entrambi JRMP e IIOP. Un server o un client scritti per lavorare con RMI-IIOP non necessitano di essere riscritti o ricompilati per supportare l'uno o l'altro; per il client infatti è sufficiente modificare alcuni parametri operativi della JVM o direttamente all'interno del codice Java, mentre un oggetto remoto (server-side) potrà essere esposto in modo da supportare entrambi i protocolli grazie al cosiddetto dual-export (vedi oltre).
La linea tratteggiata in figura 2 rappresenta una situazione particolare: in determinate situazione può accadere che una applicazione client RMI-IIOP non sia in grado di invocare oggetti CORBA. Questo può avvenire fondamentalmente per la differente semantica dei tipi definiti dall'IDL CORBA che rappresenta un super set di quelli RMI-IIOP. Può accadere quindi che in determinate situazioni, tipicamente in tutti quei casi in cui un client Java RMI-IIOP debba integrarsi con oggetti CORBA preesistenti (legacy objects), non sia possibile la comunicazione.
E' però vero che, grazie al compilatore rmic, presente nel JDK, è possibile creare il file IDL dagli oggetti Java RMI-IIOP: a partire dall'IDL si potrà generare un oggetto CORBA ad esempio in C++, oggetto che sarà invocabile da un client C++ CORBA, ma anche, e senza nessuna limitazione, da uno Java basato su RMI-IIOP.
Si potrebbe quindi dire che l'incompatibilità sia un problema esclusivamente di implementazione tale da non inficiare la comunicazione fra i due strati della figura 2.



Figura 3 -
Tramite Java IDL si può connettere il
mondo Java direttamente con CORBA

In quei casi in cui non sia possibile riscrivere l'oggetto CORBA ed il mapping non permetta a RMI-IIOP di interagire con tali oggetto, come valida alternativa si può pensare di abbandonare completamente RMI e passare a Java IDL (vedi [JIDL]). Tramite Java IDL, una delle tecnologie introdotte con Java2, è possibile accedere ad un oggetto CORBA direttamente da Java, senza passare per altri protocolli bridge intermediari. E' anche possibile fare il viceversa, ovvero esporre un oggetto Java al mondo CORBA, ma per tale scenario è sicuramente preferibile utilizzare RMI-IIOP.
Il punto di forza di RMI-IIOP è dato dal fatto che lascia inalterata la semantica di RMI (ed anche la sintassi, eccezion fatta per alcune piccole modifiche del codice), aggiungendo alcune importanti modifiche a CORBA in modo da aumentarne le funzionalità: in CORBA infatti è stata introdotta con la versione 2.3 della specifica il passaggio dei parametri per valore (object by value) già presente in RMI tramite il concetto di serializzazione dei parametri ed il Java-to-IDL mapping che consente il mapping dei tipi Java sui tipi CORBA.
Queste introduzioni, specie la prima, non devono essere sottovalutate, dato che sono di fatto variazioni molto profonde, accettate da OMG non senza qualche timore.

 

Creare un oggetto remoto
La realizzazione di un oggetto remoto conforme con lo standard RMI-IIOP è molto simile a quello di quello basato sul protocollo JRMP. A parte alcune piccole differenze nel codice, che saranno affrontate successivamente, il processo di compilazione prevede l'utilizzo del parametro -iiop da passare al compilatore rmic. In tal modo il compilatore produce stub e skeleton conformi a IIOP invece che solamente a JRMP.


Figura 4 -
il processo di sviluppo di un oggetto Java RMI-IIOP

Ovviamente il passaggio a RMI-IIOP comporta alcune importanti differenze funzionali dovute alla presenza di CORBA: ad esempio in questo caso non è disponibile il garbage collector distribuito come in RMI.
A parte questo il programmatore non dovrebbe avere altra considerazione della differente architettura sottostante.
Questo è il punto in cui la teoria Java RMI finisce e ci si addentra nel mondo di CORBA: dato che l'obiettivo di questo articolo non è quello di fare una trattazione approfondita su tale tecnologia, si rimanda alla bibliografia per maggiori approfondimenti in merito.
Da un punto di vista implementativo per realizzare un oggetto remoto la prima cosa da fare è estendere dalla classe PortableRemoteObject al posto della Remote di RMI.
Si supponga ad esempio di voler creare un oggetto remoto che restituisca l'ora locale del server in cui viene eseguito. Nella versione RMI questo oggetto potrebbe essere così definito

public class MyRemoteClock implements MyRemoteClockRemote {
  public String getRemoteDate() throws RemoteException{
    return new Date().toString();
  }
}

che in RMI-IIOP dovrebbe essere trasformato

public class MyRemoteClock
             extends PortableRemoteObject
             implements MyRemoteClock {
  public String getRemoteDate() throws RemoteException{
    return new Date().toString();
  }
}

L'altra modifica lato server da effettuare riguarda la procedura di registrazione dell'oggetto nel registry. Dato che in questo caso infatti viene utilizzato JNDI (vedi [JNDI])come sistema di name service, al posto della istruzione

naming.rebind(<nome-oggetto>, <istanza-oggetto>);

si dovrà utilizzare

naming.rebind(<nome-oggetto>, <istanza-oggetto>);

Infine dopo aver generato stub e skeleton con il comando

rmic -iiop MyRemoteClock

si dovrà procedere ad attivare il registry, utilizzando il comando tnameserv (al posto di rmiregistry).
Su lato client invece si dovranno effettuare solo le modifiche relative al differente modo di effettuare il lookup dell'oggetto remoto, basato su JNDI invece che sul rmiregistry. In questo caso si dovrà scrivere

InitialContext ic = new InitialContext(env)
Object obj = ic.lookup(nome-oggetto);
MyRemoteClock mrc = (MyRemoteClock) PortableRemoteObject.narrow(obj, MyRemoteClock.class);

A questo punto il client potrà utilizzare l'oggetto mrc in modo del tutto analogo al caso RMI, ignorando se l'implementazione sia data da un oggetto Java RMI o da uno CORBA scritto in C++.

 

Conclusione
Come si è potuto vedere RMI-IIOP offre in modo del tutto trasparente l'interazione fra Java RMI e CORBA. Il motivo per cui di recente se ne parla sempre più spesso è dovuto al suo utilizzo nell'ambito EJB. Molti application server infatti implementano i bean in esecuzione all'interno del container, con oggetti CORBA, piuttosto che con oggetti Java. Questo, sebbene non abbia nessuna ripercussione sui bean ne sul client, gli oggetti CORBA sono creati al momento del deploy, permette un sostanziale aumento delle performance, nonché l'interazione di EJB con tecnologie differenti.

 

Bibliografia
[JIDL] - "Java + IDL = CORBA" di Lorenzo Bettini, MokaByte 22, Settembre 1998, www.mokabyte.it/1998/09
[JNDI] - "Java Naming and Directory Interface API" e seguenti, di Giovanni Puliti, MokaByte 66, Settembre 2002, www.mokabyte.it/2002/09

MokaByte® è un marchio registrato da MokaByte s.r.l. 
Java®, Jini® e tutti i nomi derivati sono marchi registrati da Sun Microsystems.
Tutti i diritti riservati. E' vietata la riproduzione anche parziale.
Per comunicazioni inviare una mail a info@mokabyte.it