import java.rmi.*; public interface iCalendar extends Remote { java.util.Date dammiData() throws RemoteException; } // un’interfaccia serve a definire un prototipo di classe, senza nessuna //implementazione //========================= SERVER ========================== import java.util.Date; import java.rmi.*; import java.rmi.registry.*; import java.rmi.server.*; public class CalendarImpl extends UnicastRemoteObject implements iCalendar { public CalendarImpl () throws RemoteException{} // costruttore vuoto public Date dammiData()throws RemoteException { return new Date(); } // impl. metodo del prototipo public static void main(String s[]) { CalendarImpl cal; try { LocateRegistry.createRegistry(1099); //crea una voce di registro cal=new CalendarImpl(); Naming.bind("rmi:///CalendarImpl",cal); // collega alla voce di //registro l’oggetto cal, rappresentante della classe CalendarImpl (per esportarlo) System.out.println("Pronto per RMI"); } catch (Exception e) { e.printStackTrace(); } } } //========================= CLIENT ========================== import java.util.Date; import java.rmi.*; public class CalendarUser { public CalendarUser() {} public static void main (String s[]) { long t1=0, t2=0; Date data1,data2; iCalendar remoteCal; try { remoteCal =(iCalendar) Naming.lookup("rmi://x1/CalendarImpl"); data1=remoteCal.dammiData(); // invocaz. di un metodo remoto t1=data1.getTime(); for (long i=1; i<90000000;i++);// perde un po’ di tempo data2=remoteCal.dammiData(); // invocaz. di un metodo remoto t2=data2.getTime(); } catch (Exception e) { e.printStackTrace(); } System.out.println("Questa chiamata RMI ha richiesto la differenza tra "+ t1+" e "+t2+" millisecondi, ossia "+(t2-t1)); } } La classe CalendarImpl crea ed esporta un oggetto remoto (un oggetto, cioè, rappresentante di questa classe). L’esportazione è resa possibile da extends UnicastRemoteObject e dalla registrazione e assegnazione al registro; inserendo infatti un oggetto in registro, lo si rende disponibile per i client su altre macchine (virtuali). La classe CalendarUser cerca l’oggetto remoto in un registro e richiama il metodo dammiData() definito per l’oggetto remoto. Dopo aver inserito un oggetto in un registro, infatti, qualsiasi client può ottenere un riferimento all’oggetto remoto specificando il nome della macchina, il numero della porta (se diverso da quello predefinito, che vale 1099) e il nome attribuito all’oggetto quando questo è stato messo nel registro. Concludendo, CalendarImpl definisce l’implementazione dell’oggetto remoto. Un oggetto date viene creato nel server (return new Date()) e una copia viene inviata al client (data1=remoteCal.dammiData();). Il metodo dammiData() viene chiamato due volte per vedere quanto tempo passa. SERVER CLIENT scheletro stub Livello di comunicazione percepito Livello di comunicazione effettivo Quando un client richiama un metodo remoto, si ha l’illusione di richiamare direttamente il metodo sull’oggetto remoto. In realtà la chiamata al metodo remoto inizia come chiamata a un metodo locale in uno stub. Lo stub raggruppa in pacchetti tutti i parametri e invia la richiesta allo scheletro dell’oggetto remoto; lo scheletro suddivide i parametri inviati e inoltra la chiamata al metodo di destinazione. Lo stub e lo scheletro sono responsabili di smistare i valori restituiti. SERVER (sulla macchina x1) C:\>Dir ->(CalendarImpl.java, iCalendar.java) C:\>javac CalendarImpl.java C:\>rmic CalendarImpl C:\>dir -> (CalendarImpl.java, iCalendar.java, CalendarImpl.class, CalendarImpl_Stub.class, CalendarImpl_Skel.class) C:\>copy CalendarImpl_Stub.class e iCalendar.java sul client C:\>java CalendarImpl Pronto per RMI CLIENT C:\>dir -> (CalendarUser.java, iCalendar.java, CalendarImpl_Stub.class) C:\>javac CalendarUser.java C:\>dir -> (CalendarUser.java, CalendarUser.class, iCalendar.java, CalendarImpl_Stub.class) C:\>java CalendarUser Questa chiamata RMI ha richiesto la differenza tra 12345678500 e 12345678901 millisecondi, ossia 401