Java RMI: Esempio Completo di un Applicazione Distribuita



Documenti analoghi
RMI Remote Method Invocation

RMI. Java RMI RMI. G. Prencipe

Socket & RMI Ingegneria del Software - San Pietro

Programmazione distribuita

Organizzazione della lezione. Lezione 18 Remote Method Invocation - 6. (con callback) L accesso al registry per il rebind()

UnicastRemoteObject. Massimo Merro Programmazione di Rete 103 / 124

Java Remote Method Invocation

Registri RMI. Massimo Merro Univ. Verona Programmazione di Rete 90 / 247

Esercitazioni 7 e 8. Bounded Buffer con sincronizzazione Java (1)

Java Virtual Machine

Java threads (2) Programmazione Concorrente

7 Esercitazione (svolta): Callback. Polling. Java RMI: callback. Server. Server. Client. Client. due possibilità:

La gestione dell input/output da tastiera La gestione dell input/output da file La gestione delle eccezioni

Programmazione di sistemi distribuiti

Mobilità di Codice. Massimo Merro Programmazione di Rete 128 / 144

Esercitazione di Sistemi Distribuiti: Java RMI

RMI: metodi equals e hashcode

Progettazione : Design Pattern Creazionali

Programmazione ad Oggetti Modulo A (Esame del 11/9/2015)

15 - Packages. Programmazione e analisi di dati Modulo A: Programmazione in Java. Paolo Milazzo

Laboratorio di Sistemi Distribuiti Leonardo Mariani

Compute engine generici in RMI

Tipi primitivi. Ad esempio, il codice seguente dichiara una variabile di tipo intero, le assegna il valore 5 e stampa a schermo il suo contenuto:

SISTEMI OPERATIVI. Sincronizzazione in Java (Monitor e variabili condizione in Java)

14 - Packages. Programmazione e analisi di dati Modulo A: Programmazione in Java. Paolo Milazzo

Programmazione a Oggetti Lezione 10. Ereditarieta

Parte II: Reti di calcolatori Lezione 10

SAPIENZA Università di Roma Facoltà di Ingegneria dell Informazione, Informatica e Statistica

Parte II: Reti di calcolatori Lezione 12

GESTIONE DEI PROCESSI

Main System Monitor Keyboard

MODELLO CLIENT/SERVER. Gianluca Daino Dipartimento di Ingegneria dell Informazione Università degli Studi di Siena

Corso di Linguaggi di Programmazione

Lezione 1 Introduzione

Esercitazioni di Progettazione del Software. Esercitazione (Prova al calcolatore del 17 settembre 2010)

Test di unità con JUnit4

Supermarket Progetto di Programmazione Febbraio 2010

JNDI. Massimo Merro Programmazione di Rete 214 / 229

Remote Method Invocation (RMI)

(VHUFLWD]LRQLGLEDVHVXOOH6RFNHWLQ-DYD 6RFNHWGLWLSRGDWDJUDP

Esercitazione n 4. Obiettivi

Sistemi Operativi (modulo di Informatica II)

Un esercizio d esame. Flavio De Paoli

12 - Introduzione alla Programmazione Orientata agli Oggetti (Object Oriented Programming OOP)

Siti web centrati sui dati Architettura MVC-2: i JavaBeans

Introduzione a Java Remote Method Invocation (RMI)

Linguaggi Corso M-Z - Laurea in Ingegneria Informatica A.A Esercitazione. Programmazione Object Oriented in Java

SOMMARIO Coda (queue): QUEUE. QUEUE : specifica QUEUE

Appunti di Sistemi Distribuiti

SAPIENZA Università di Roma, Facoltà di Ingegneria

Ottava Esercitazione. introduzione ai thread java mutua esclusione

Programmazione Orientata agli Oggetti in Linguaggio Java

10.1. Un indirizzo IP viene rappresentato in Java come un'istanza della classe InetAddress.

Appunti di Informatica 1

Concetti Base Eccezioni Eccezioni e Metodi Gerarchia di Eccezioni. Java: Eccezioni. Damiano Macedonio

Soluzione dell esercizio del 2 Febbraio 2004

Servers Activatable. Massimo Merro Programmazione di Rete 166 / 193

Protocolli applicativi: FTP

Il linguaggio Java. Oggetto remoto. Remote Method Invocation (RMI) Oggetto remoto: oggetto i cui metodi possono essere invocati attraverso la rete

RMI. Prova pratica di Sistemi Distribuiti:

Corso di Reti di Calcolatori L-A

Fondamenti di Informatica 1. Prof. B.Buttarazzi A.A. 2010/2011

Realizzazione di una classe con un associazione

Java: Compilatore e Interprete

Reflection in Java. Linguaggi Corso M-Z - Laurea in Ingegneria Informatica A.A

Architettura MVC-2: i JavaBeans

Tecnologie di Sviluppo per il Web

2.5. L'indirizzo IP identifica il computer di origine, il numero di porta invece identifica il processo di origine.

Realizzazione di Politiche di Gestione delle Risorse: i Semafori Privati

Registratori di Cassa

Operazioni di input/output. Prof. Francesco Accarino IIS Altiero Spinelli Via Leopardi 132 Sesto San Giovanni

Sistemi Operativi. Lez. 13: primitive per la concorrenza monitor e messaggi

Prova d Esame Compito B

Approccio stratificato

La concorrenza in Java package java.util.concurrent Antonio Furone

Esercizi sul Monitor in Java

Istruzioni di installazione di IBM SPSS Modeler Text Analytics (licenza per sito)

Java:Struttura di Programma. Fabio Scanu a.s. 2014/2015

Corso di Amministrazione di Reti A.A. 2002/2003

Per scrivere una procedura che non deve restituire nessun valore e deve solo contenere le informazioni per le modalità delle porte e controlli

Indirizzi Internet e. I livelli di trasporto delle informazioni. Comunicazione e naming in Internet

Come funziona il WWW. Architettura client-server. Web: client-server. Il protocollo

ProgettAzione tecnologie in movimento - V anno Unità 4 - Realizzare applicazioni per la comunicazione in rete

Multithreading in Java. Fondamenti di Sistemi Informativi

Gestione Risorse Umane Web

3 - Variabili. Programmazione e analisi di dati Modulo A: Programmazione in Java. Paolo Milazzo

Organizzazione della lezione. 15. Java Remote Method Invocation (3) Lo schema del Factory Design Pattern - 1. Factory design pattern

FPf per Windows 3.1. Guida all uso

Modulo 4: Ereditarietà, interfacce e clonazione

Manuale per la configurazione di un account di PEC in Mozilla.

Contesto e motivazioni Architettura e concetti di base Componenti di RMI RMIRegistry Interfacce, eccezioni e classi Lo sviluppo di una applicazione L

Gestione delle Eccezioni

Prova d Esame Compito A

Corso sul linguaggio Java

Oggetti Lezione 3. aspetti generali e definizione di classi I

11/02/2015 MANUALE DI INSTALLAZIONE DELL APPLICAZIONE DESKTOP TELEMATICO VERSIONE 1.0

ARCHITETTURA DI RETE FOLEGNANI ANDREA

19. LA PROGRAMMAZIONE LATO SERVER

Activation In sintesi: è inutile avere attivi degli oggetti se non vengono utilizzati

Coordinazione Distribuita

Transcript:

Java RMI: Esempio Completo di un Applicazione Distribuita Il Problema Produttore/Consumatore in Ambiente Distribuito* *a cura del Prof. L. Nigro, Università della Calabria

Java RMI (Remote Method Invocation) Introduce uno strato di trasporto basato su TCP, per la chiamata e trasmissione di dati (opportunamente espressi in un formato di rete; Java usa la serializzazione come tecnica di marshalling) ) ad un oggetto remoto Un oggetto remoto è rappresentato presso il client da uno stub (proxy), che implementa la stessa interfaccia dell oggetto remoto.. Lo stub riceve la richiesta di invocazione di un metodo, prepara un blocco di informazioni (messaggio)) e lo spedisce alla macchina server dove risiede l oggetto remoto (oggetto effettivo), utilizzando i servizi di TCP Presso il server è presente lo skeleton che si interfaccia con la rete, converte le informazioni ricevute dallo stub, chiama il metodo effettivo sull oggetto remoto e, alla fine, costruisce un messaggio col risultato che è inviato allo stub e quindi al client Lo schema complessivo mira a rendere indistinguibile la chiamata di un metodo su un oggetto locale da quella relativa ad un oggetto remoto (semantica sincrona o bloccante) RMI richiede la mobilità del codice di classi Java e utilizza un meccanismo di garbage collection distribuita degli oggetti remoti basata su reference-count count IS_7 - L. Nigro 51

Architettura IS_7 - L. Nigro 52

Osservazioni Le prime versioni di Java effettivamente generavano stub e skeleton di un oggetto remoto Java 1.4 si limita a generare solo la componente stub Le ultime versioni (Java 5.0 o superiore) ) non generano più esplicitamente stub e skeleton dal momento che il linguaggio ne fornisce direttamente il supporto (basato sulla reflection e i proxy dinamici) indipendentemente dal particolare oggetto remoto implementato Ottenere un applicazione distribuita funzionante basata su Java RMI può essere non agevole dal momento che occorre padroneggiare tutta una serie di dettagli.. In quanto segue si mostrerà l uso di RMI attraverso lo sviluppo concreto di esempio non banale, rappresentativo della situazione generale I concetti base sono: progetto interfacce remote (da( collocare identicamente lato server e lato client) implementazioni delle interfacce lato server (UnicastRemoteObject( UnicastRemoteObject) pubblicazione di uno o più oggetti remoti su rmiregstry implementazioni delle applicazioni client con, es., lookup di oggetto remoti su rmiregistry predisposizione di un web server per il download di classi a runtime. IS_7 - L. Nigro 53

Produttore/consumatore/buffer limitato in ambiente distribuito Si tratta di un problema classico di programmazione concorrente Un certo numero di processi produttori e consumatori comunicano tra loro scambiandosi messaggi di un tipo generico, attraverso la mediazione di un buffer limitato (mailbox) Il buffer va realizzato in veste thread-safe mediante una scelta opportuna del meccanismo di controllo della concorrenza Il buffer costituisce un oggetto remoto condiviso tra i produttori e consumatori dispersi su varie macchine (dunque il problema coinvolge il vero parallelismo) Come meccanismi di controllo della concorrenza si considerano: semafori, lock/condition, monitor nativo di Java Si desidera che i risvegli dei processi avvengano in ordine FIFO Il buffer rappresenta il server, i processi produttori/consumatori i client IS_7 - L. Nigro 54

Impostazione del progetto Il progetto viene sviluppato su singola macchina ma è pensato esplicitamente per il distribuito. Tutto ciò si riflette,, ad esempio, nel controllo degli accessi alle classi che in una JVM è mediato dal classpath Sviluppare secondo RMI significa comprendere esattamente che il sistema software deve poter girare indipendentemente da ogni agevolazione di classpath Concretamente, è utile suddividere il lavoro in tre progetti associati rispettivamente al lato server, al lato client, agli aspetti comuni (common). Tali progetti possono essere sviluppati in ambiente Eclipse (dopo( aver scaricato dalla rete ed installato il plug-in di Java RMI) o direttamente utilizzando gli strumenti Java (il( metodo preferito di seguito) Siano bb_server, bb_client e bb_common le tre directory (es( es. di c:\) dei progetti. Siccome le varie componenti dell applicazione distribuita gireranno su macchine (e JVM) diverse, l utilizzo del packaging deve avvenire rigorosamente in modo congruente nei vari sotto progetti Si sottolinea ancora che le classi interne a bb_server o bb_client o bb_common non devono basarsi sul classpath per ottenere l accesso a classi degli altri progetti.. A tale proposito, si ammette che sulla macchina di sviluppo locale il classpath non contenga gli entry point di bb_server, bb_client e bb_common IS_7 - L. Nigro 55

Le interfacce Il punto di partenza è la definizione di opportune interfacce lato server Siccome le specifiche richiedono di poter lavorare su bounded buffer basati su diversi metodi di concorrenza, si è deciso di introdurre un factory che ottiene, a partire da informazioni di configurazione,, la dimensione del buffer e la specifica del tipo di controllo della concorrenza L oggetto factory è di fatto il primo oggetto remoto da realizzare. Altri oggetti remoti sono poi i vari tipi di buffer Le interfacce BoundeBuffer e BoundedBufferFactory rappresentano aspetti comuni dell intero progetto. Esse vengono sviluppate in bb_common e poi replicate identicamente (rispettando la struttura a package) in bb_server e bb_client Tanto BoundedBuffer quanto BoundedBufferFactory estendono l interfaccia Remote e i loro metodi devono dichiarare che possono sollevare l eccezione RemoteException (di tipo checked) Ogni (sotto) progetto ha package del tipo is.sottodirectory, il che significa che una corrispondente gerarchia di directory va realizzata in bb_common,, o bb_server etc. Ad esempio, siccome si desidera il package is.boundedbuffer per le interfacce BoundedBuffer e BoundedBufferFactory,, in bb_common si crea la directory is e al suo interno boundedbuffer etc. IS_7 - L. Nigro 56

Le interfacce di is.boundedbuffer package is.boundedbuffer; import java.rmi.*; public interface BoundedBuffer extends Remote{ public void put( Message m ) throws RemoteException; public Message get() throws RemoteException; //BoundedBuffer package is.boundedbuffer; import java.rmi.*; public interface BoundedBufferFactory extends Remote{ public BoundedBuffer getbuffer() throws RemoteException; //BoundedBufferFactory IS_7 - L. Nigro 57

Le interfacce di is.boundedbuffer In realtà, il package is.boundedbuffer dichiara anche l interfaccia Message che descrive la tipologia generica dei messaggi scambiati Message non è un interfaccia remota,, ma estende Serializable. Metodi esistono per fissare/ottenere il dato di un messaggio,, e per fissare/ottenere il tempo di permanenza del messaggio nel buffer package is.boundedbuffer; import java.io.*; public interface Message extends Serializable{ public void setdata( Object dato ); public Object getdata(); public long getbuffertime(); public void setbuffertime( long time ); //Message IS_7 - L. Nigro 58

Problemi di compilazione Dopo aver creato e compilato in bb_common le classi di is.boundedbuffer, si copia la gerarchia di directory is/boundedbuffer all interno di bb_server e bb_client Attenzione: l impostazione del lavoro richiede che per compilare correttamente es.. le interfacce di is.boundedbuffer, ci si debba collocare col prompt di sistema (uso di javac a riga di comando) ) in bb_common. Da dentro Eclipse, ovviamente,, le cose risulterebbero semplificate dallo strumento Utile è un file batch (es( es. jc.bat) posto in bb_common, col seguente contenuto: javac is/boundedbuffer boundedbuffer/*.java IS_7 - L. Nigro 59

Implementazioni lato server In bb_server si crea la sottodirectory di is es. denominata boundedbuffer_server, che si affianca alla sottodirectory boundedbuffer copiata da bb_common In boundedbuffer_server si programma l oggetto BoundedBufferFactoryImpl implementazione di BoundedBufferFactory ed erede di UnicastRemoteObject.. In questo modo l oggetto remoto (factory) si esporta ad RMI. L esportazione significa che RMI si fa poi carico di sentire richieste di connessioni dall esterno esterno, su una certa porta, dirette all oggetto remoto Nella stessa directory si implementano le classi bounded buffer concrete IS_7 - L. Nigro 60

BoundedBufferFactoryImpl Scopo di questa classe è consultare un file di properties (buffer.properties( buffer.properties) ) ed ottenere da questo le informazioni sulla buffer size ed il tipo di controllo della concorrenza. Esempio di contenuto di buffer.properties: BufferSize=5 ConcurrencyMethod=Semaphore Gli altri metodi di concorrenza sono indicati dai valori Lock e Native di ConcurrentMethod Se viene sollevata qualche eccezione (es. il file di properties non viene trovato) ) la classe ipotizza il controllo di concorrenza Native con una buffer size di default di 5 slot IS_7 - L. Nigro 61

BoundedBufferFactoryImpl package is.boundedbuffer_server; import is.boundedbuffer.*; import java.rmi.*; import java.rmi.server.*; import java.util.properties; import java.io.*; public class BoundedBufferFactoryImpl extends UnicastRemoteObject implements BoundedBufferFactory{ private BoundedBuffer bb=null; public BoundedBufferFactoryImpl() throws RemoteException{ public BoundedBuffer getbuffer() throws RemoteException{ if( bb!=null ) return bb; Properties p=new Properties(); int n=5;//dimensione di default IS_7 - L. Nigro 62

BoundedBufferFactoryImpl try{ FileInputStream in= new FileInputStream("c:\\bb_server\\is\\boundedbuffer_server\\buffer.properties"); p.load( in ); String size=p.getproperty("buffersize"); n=integer.parseint(size); System.out.println("buffer size="+n); String conctype=p.getproperty("concurrencymethod"); if( conctype.equalsignorecase("semaphore") ){ System.out.println("Semaphore"); bb=new BoundedBufferSemaphoreImpl(n); else if( conctype.equalsignorecase("lock") ){ System.out.println("Lock/Condition"); bb=new BoundedBufferLockImpl(n); else{//monitor nativo di default System.out.println("Java Native Monitor"); bb=new BoundedBufferSynchronizedImpl(n); catch( IOException e ){ e.printstacktrace(); System.out.println("Java Native Monitor"); bb=new BoundedBufferSynchronizedImpl(n); return bb; //getbuffer //BoundedBufferFactoryImpl IS_7 - L. Nigro 63

Le classi degli oggetti remoti bounded buffer Per facilitare lo sviluppo si è deciso di realizzare preliminarmente la classe BoundedBufferImpl che implementa BoundedBuffer ma senza alcun controllo della concorrenza L uso di questa classe da parte di più thread è unsafe Le classi eredi aggiungono il controllo della concorrenza,, ma si disinteressano della gestione del buffer IS_7 - L. Nigro 64

BoundedBufferImpl package is.boundedbuffer_server; import is.boundedbuffer.*; import java.rmi.*; import java.rmi.server.*; public class BoundedBufferImpl extends UnicastRemoteObject implements BoundedBuffer{//bounded buffer non sincronizzato private Message[] buffer; private int n, in, out, count; public BoundedBufferImpl( int n ) throws RemoteException{ if( n<=0 ) throw new RemoteException ("La dimensione del buffer deve essere positiva!"); this.n=n; buffer=new Message[n]; in=0; out=0; count=0; //costruttore IS_7 - L. Nigro 65

BoundedBufferImpl public void put( Message x ) throws RemoteException{ buffer[in]=x; in=(in+1)%n; count++; System.out.println("Buffering "+x+"..."); x.setbuffertime( System.currentTimeMillis() ); //put public Message get() throws RemoteException{ Message x=buffer[out]; out=(out+1)%n; count--; x.setbuffertime( System.currentTimeMillis()-x.getBufferTime() ); System.out.println("Unbuffering "+x+"..."); return x; //get protected boolean empty(){ return count==0; protected boolean full(){ return count==n; //BoundedBufferImpl IS_7 - L. Nigro 66

BoundedBufferSemaphoreImpl package is.boundedbuffer_server; import java.util.concurrent.*; import is.boundedbuffer.*; import java.rmi.*; import java.rmi.server.*; public class BoundedBufferSemaphoreImpl extends BoundedBufferImpl{ private Semaphore mutex=new Semaphore(1,true); private Semaphore empty, full; public BoundedBufferSemaphoreImpl( int n ) throws RemoteException{ super(n); empty=new Semaphore(n,true); full=new Semaphore(0,true); public void put( Message x ) throws RemoteException{ empty.acquireuninterruptibly(); mutex.acquireuninterruptibly(); super.put(x); mutex.release(); full.release(); //put public Message get() throws RemoteException{ full.acquireuninterruptibly(); mutex.acquireuninterruptibly(); Message x=super.get(); mutex.release(); empty.release(); return x; //get //BoundedBufferSemaphoreImpl IS_7 - L. Nigro 67

BoundedBufferLockImpl package is.boundedbuffer_server; import java.util.concurrent.locks.*; import is.boundedbuffer.*; import java.rmi.*; import java.rmi.server.*; import java.util.*; public class BoundedBufferLockImpl extends BoundedBufferImpl{ private Lock lock=new ReentrantLock(); private Condition empty=lock.newcondition(); private Condition full=lock.newcondition(); private List<Thread> listaproduttori=new ArrayList<Thread>(); private List<Thread> listaconsumatori=new ArrayList<Thread>(); private boolean produttoredevedormire(){ if( super.full() listaproduttori.get(0)!=thread.currentthread() ) return true; return false; //produttoredevedormire private boolean consumatoredevedormire(){ if( super.empty() listaconsumatori.get(0)!=thread.currentthread() ) return true; return false; //consumatoredevedormire public BoundedBufferLockImpl( int n ) throws RemoteException{ super(n); //costruttore IS_7 - L. Nigro 68

BoundedBufferLockImpl public void put( Message x ) throws RemoteException{ lock.lock(); try{ listaproduttori.add( Thread.currentThread() ); while( produttoredevedormire() ){ full.awaituninterruptibly(); listaproduttori.remove(0); super.put(x); empty.signalall(); finally{ lock.unlock(); //put public Message get() throws RemoteException{ Message x; lock.lock(); try{ listaconsumatori.add( Thread.currentThread() ); while( consumatoredevedormire() ){ empty.awaituninterruptibly(); listaconsumatori.remove(0); x=super.get(); full.signalall(); finally{ lock.unlock(); return x; //get //BoundedBufferLockImpl IS_7 - L. Nigro 69

BoundedBufferSynchronizedImpl package is.boundedbuffer_server; import is.boundedbuffer.*; import java.rmi.*; import java.rmi.server.*; import java.util.*; public class BoundedBufferSynchronizedImpl extends BoundedBufferImpl{ private List<Thread> listaproduttori=new ArrayList<Thread>(); private List<Thread> listaconsumatori=new ArrayList<Thread>(); private boolean produttoredevedormire(){ if( super.full() listaproduttori.get(0)!=thread.currentthread() ) return true; return false; //produttoredevedormire private boolean consumatoredevedormire(){ if( super.empty() listaconsumatori.get(0)!=thread.currentthread() ) return true; return false; //consumatoredevedormire public BoundedBufferSynchronizedImpl( int n ) throws RemoteException{ super(n); //costruttore IS_7 - L. Nigro 70

BoundedBufferSynchronizedImpl public synchronized void put( Message x ) throws RemoteException{ listaproduttori.add( Thread.currentThread() ); while( produttoredevedormire() ){ try{ wait(); catch( InterruptedException e ){ listaproduttori.remove(0); super.put(x); notifyall(); //put public synchronized Message get() throws RemoteException{ listaconsumatori.add( Thread.currentThread() ); while( this.consumatoredevedormire() ){ try{ wait(); catch( InterruptedException e ){ listaconsumatori.remove(0); Message x=super.get(); notifyall(); return x; //get //BoundedBufferSynchronizedImpl IS_7 - L. Nigro 71

Implementazione del server package is.boundedbuffer_server; import is.boundedbuffer.*; import java.rmi.*; import java.rmi.server.*; import javax.naming.*; public class BoundedBufferServer{ public static void main( String[] args ){ System.setProperty("java.security.policy", "c:\\bb_server\\is\\boundedbuffer_server\\server.policy"); System.setSecurityManager( new RMISecurityManager() ); try{ System.out.println("Costruzione factory..."); BoundedBufferFactory bbf=new BoundedBufferFactoryImpl(); System.out.println("Pubblicazione factory..."); Context naming=new InitialContext(); naming.rebind("rmi:boundedbufferfactory",bbf); System.out.println("In attesa di clienti..."); catch( Exception e ){ e.printstacktrace(); //main //BoundedBufferServer IS_7 - L. Nigro 72

Commenti Un programma server possiede il main ed il suo scopo è creare e pubblicare uno o più oggetti remoti di cui i client potranno scaricare lo stub su richiesta La pubblicazione sfrutta il servizio rmiregistry fornito da Java, che memorizza coppie <nome,riferimento> di oggetti remoti L utilizzo del servizio rmiregistry avviene mediante la classe Context di cui si crea un oggetto naming. Il metodo rebind inserisce una nuova coppia ed eventualmente aggiorna l oggetto se il nome è già presente.. I nomi sono del tipo rmi:nome_oggetto È importante assicurare nomi unici globali per gli oggetti remoti Nell esempio esempio,, solo l oggetto factory è creato e pubblicato sotto il nome rmi:boundedbufferfactory.. Un oggetto bounded buffer non viene pubblicato ma egualmente potrà essere ottenuto da un client invocando getbuffer() sul factory, che cosi restituisce lo stub del bounded buffer. Tutto ciò, tra l altro, assicura che i vari client ottengano e cooperino utilizzando uno stesso oggetto remoto bounded buffer IS_7 - L. Nigro 73

Commenti La compilazione di BoundedBufferServer implicitamente genera lo stub associato (in realtà Java 5.0 o superiore non lo genera più) Utilizzando una versione di Java sino alla 1.4, lo stub andrebbe creato esplicitamente col compilatore rmic come segue: >rmic is.boundedbuffer_server.boundedbufferserver invocato da dentro bb_server e specificando esplicitamente il package. Si otterrebbe il file BoundedBufferServer_Stub.class rmiregistry, una volta contattato, fornisce ad un client lo stub di un oggetto remoto pubblicato.. A questo scopo lo stub dovrebbe essere disponibile come una risorsa comune (si veda più avanti) ) cui rmiregistry può attingere on-demand IS_7 - L. Nigro 74

Implementazioni lato client Si presentano due processi client: uno con funzioni di produttore di messaggi,, un altro come consumatore.. Le relative classi (provviste del main) sono parte delle sotto directory boundedbuffer_producer e boundedbuffer_consumer di is di bb_client Il produttore ottiene un messaggio alla volta da tastiera e lo scrive sul buffer remoto Il consumatore, ogni qualvolta l utente digita Invio, chiede un messaggio al buffer e lo consuma, nel senso che ne mostra il contenuto su video unitamente al tempo di stazionamento del messaggio nel buffer Ma come è fatto un messaggio? È responsabilità del producer definire la tipologia dei messaggi scambiati In concreto, nella sotto directory boundedbuffer_producer si introduce la classe PCMessage che al momento risulta sconosciuta tanto al server (bounded buffer) quanto ai client consumer. La classe PCMessage verrà ottenuta dinamicamente dal server e dai consumatori sfruttando la mobilità del codice (si veda più avanti) presente in RMI IS_7 - L. Nigro 75

Classe PCMessage package is.boundedbuffer_producer; import java.io.*; import is.boundedbuffer.*; public class PCMessage implements Message, Serializable{ private long waittime; String content; public PCMessage( String s ){ content=s; public void setdata( Object s ){ content=(string)s; public Object getdata(){ return content; public void setbuffertime( long time ){ waittime=time; public long getbuffertime(){ return waittime; public String tostring(){ return content; //tostring //PCMessage IS_7 - L. Nigro 76

ProducerClient package is.boundedbuffer_producer; import is.boundedbuffer.*; import java.rmi.*; import java.rmi.server.*; import javax.naming.*; import java.util.*; public class ProducerClient{ public static void main( String[] args ){ System.setProperty("java.security.policy", "c:\\bb_client\\is\\boundedbuffer_producer\\client.policy"); System.setSecurityManager( new RMISecurityManager() ); String url="rmi://localhost/"; //prefisso url della macchina remota del server BoundedBufferFactory factory=null; BoundedBuffer bb=null; try{ Context naming=new InitialContext(); factory=(boundedbufferfactory)naming.lookup(url+"boundedbufferfactory"); bb=factory.getbuffer(); catch( Exception e ){ e.printstacktrace(); Scanner sc=new Scanner( System.in ); for(;;){ System.out.print("msg> "); String msg=sc.nextline(); try{ bb.put( new PCMessage(msg) ); catch( RemoteException e ){ e.printstacktrace(); //ProducerClient IS_7 - L. Nigro 77

ConsumerClient package is.boundedbuffer_consumer; import is.boundedbuffer.*; import java.util.scanner; import java.rmi.*; import java.rmi.server.*; import javax.naming.*; public class ConsumerClient{ public static void main( String[] args ){ System.setProperty("java.security.policy", "c:\\bb_client\\is\\boundedbuffer_consumer\\client.policy"); System.setSecurityManager( new RMISecurityManager() ); String url="rmi://localhost/"; BoundedBufferFactory factory=null; BoundedBuffer bb=null; try{ Context naming=new InitialContext(); factory=(boundedbufferfactory)naming.lookup( url+"boundedbufferfactory ); bb=factory.getbuffer(); catch( Exception e ){ e.printstacktrace(); Scanner sc=new Scanner( System.in ); String answer=null; Message msg=null; IS_7 - L. Nigro 78

ConsumerClient for(;;){ System.out.print("Press Invio to receive "); answer=sc.nextline(); try{ msg=(message)bb.get(); System.out.println("received msg "+msg+ " with buffer time="+msg.getbuffertime()+" ms"); catch( RemoteException e ){ e.printstacktrace(); //ConsumerClient IS_7 - L. Nigro 79