RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che...

45
RMI Remote Method Invocation da materiale di Carlo Ghezzi e Alfredo Motta

Transcript of RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che...

Page 1: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

RMIRemote Method Invocation

da materiale diCarlo Ghezzi e Alfredo Motta

Page 2: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

Verso RMI

• Un client esegue una determinata richiesta• Tale richiesta viaggia lungo la rete verso un

determinato server destinatario• Il server processa la richiesta e manda indietro la

risposta al client per essere analizzata• Con i socket però dobbiamo gestire il formato dei

messaggi e la gestione della connessione

Page 3: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

Verso RMI• Quello che cerchiamo è un meccanismo con il

quale il programmatore del client esegua una normale chiamata a metodo – senza preoccuparsi che c’è una rete di mezzo

• Per farlo la soluzione tecnologica è quella di installare un proxy sul client– Il proxy appare al client come un normale oggetto– ma maschera tutto il processo di utilizzo della rete per

eseguire il metodo sul server

• Allo stesso modo il programmatore che implementa il servizio non vuole preoccuparsi della gestione della comunicazione con il client – e per questo installa anche lui un proxy sul server

Page 4: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

Verso RMI…

Page 5: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

Le basi di RMI

• Oggetto remoto– Oggetto i cui metodi possono essere invocati da una Java

Virtual Machine diversa da quella in cui l’oggetto risiede• Interfaccia Remota

– Interfaccia che dichiara quali sono i metodi che possono essere invocati da una diversa Java Virtual Machine

• Server– Insieme di uno o più oggetti remoti che, implementando

una o più interfacce remote, offrono delle risorse (dati e/o procedure) a macchine esterne distribuite sulla rete

• Remote Method Invocation (RMI)– Invocazione di un metodo presente in una interfaccia

remota implementata da un oggetto remoto– La sintassi di una invocazione remota è identica a quella

locale

Page 6: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

Architettura interna

• Il client colloquia con un proxy locale del server detto stub– Lo stub rappresenta il server lato client– Implementa l'interfaccia del server– È capace di fare forward delle chiamate ai suoi metodi

• Esiste anche un proxy del client sul lato server, detto skeleton– È una rappresentazione del client– Chiama i servizi del server– Sa come fare forward dei risultati

• Da Java 2 gli skeleton non sono più necessari

Page 7: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

RMI Registry

• Il registro RMI si occupa di fornire al client lo Stub richiesto– In fase di registrazione il server potrà fornire un nome

canonico per il proprio oggetto remoto– Il client potrà quindi ottenere lo stub utilizzando il

nome che gli è stato assegnato

Page 8: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

Scaricare lo stub

• Il registro RMI per spedire lo stub al client ha diverse opzioni– Se il client e il server risiedono sulla stessa macchina è

possibile indicare al client il path locale per lo stub– Se il client e il server risiedono su macchine differenti è

necessario utilizzare un server HTTP per permettere al registro di spedire lo stub

Page 9: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

Riassumendo…

• Lato client– Viene richiesto a un registro RMI lo stub per l’invocazione

di un determinato oggetto remoto– I parametri in ingresso all’invocazione remota vengono

serializzati (tale processo è chiamato marshalling)– L’invocazione remota viene inviata al server

• Lato server– Il server localizza l’oggetto remoto che deve essere

invocato– Chiama il metodo desiderato passandogli i parametri

ricevuti dal client– Cattura il valore di ritorno o le eventuali eccezioni– Spedisce allo stub del client un pacchetto contenente i dati

ritornati dal metodo

Page 10: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

Esempio

• Vogliamo realizzare un’applicazione che gestisce un magazzino Il magazzino contiene un insieme di prodotti e ogni prodotto è identificato da– Una stringa che identifica il prodotto– Un prezzo

Page 11: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

Interfaccia condivisa client-server

• Interfaccia condivisa dal client e dal server, entrambi sanno che si tratta di un interfaccia remota

• I client saranno costretti a gestire gli errori che possono sorgere durante l’invocazione di un oggetto remoto

public interface WarehouseI extends Remote {double getPrice(String description) throws RemoteException;

}

Page 12: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

Warehouse Server

• Il server implementa l’interfaccia remota• Estende la classe UnicastRemoteObject che rende

l’oggetto accessibile da remoto

Page 13: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

Warehouse

public class Warehouse extends UnicastRemoteObject implements WarehouseI {private static final long serialVersionUID = 1L; //defaultprivate Map<String, Double> prices;

public Warehouse() throws RemoteException {prices = new HashMap<String, Double>();prices.put("Blackwell Toaster", 24.95);prices.put("ZapXpress Microwave Oven", 49.95);

}

public double getPrice(String description) throws RemoteException {Double price = prices.get(description);return price == null ? 0 : price;

}}

Page 14: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

Pubblicare l’oggetto remoto

• All’avvio il server pubblica sul registro RMI l’oggetto remoto

• In questo modo il client potrà cercare gli oggettiremoti disponibili e ottenere un riferimento

• Il registro RMI deve essere online prima di avviare il server– Di default il registro si trova su localhost alla porta 1099– Stiamo facendo un binding tra il nome

“central_warehouse” e l’oggetto remoto centralWarehouse

Page 15: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

Codice completo

public class WarehouseServer {public static void main(String[] args) throws RemoteException, NamingException {

System.out.println("Constructing server implementation");try {

Warehouse centralWarehouse = new Warehouse();System.out.println("Binding server impl. to registry");Registry registry= LocateRegistry.getRegistry();registry.bind("centralWarehouse", centralWarehouse);

}catch (Exception e) {

System.err.println("WarehouseServer exception");e.printStackTrace();

}System.out.println("Waiting for clients");

}}

Page 16: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

Codice completo (II)

public class WarehouseServer {public static void main(String[] args) throws RemoteException, NamingException {

System.out.println("Constructing server implementation");try {

Warehouse centralWarehouse = new Warehouse();System.out.println("Binding server impl. to registry");Registry registry= LocateRegistry.createRegistry(1099);registry.bind("centralWarehouse", centralWarehouse);

}catch (Exception e) {

System.err.println("WarehouseServer exception");e.printStackTrace();

}System.out.println("Waiting for clients");

}}

Page 17: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

module-info.java

module RMIexample {requires java.rmi;requires java.naming;exports shared to java.rmi;

}

Page 18: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

bind()

• Per ragioni di sicurezza un’applicazione può associare, deassociare o riassociare un oggetto a un nome solo se l’applicazione gira sullo stesso host del registro

• Questo evita che client malevoli cambino le informazioni del registro

• I client possono comunque richiedere tutti gli oggetti remoti

String[] remoteObjects = registry.list();

Page 19: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

getRegistry

• getRegistry() ritorna un riferimento all’oggetto remoto Registry su local host e alla porta 1099

• getRegistry(int port) ritorna un riferimento all’oggetto remoto Registry su local host e alla porta port

• getRegistry(String host) ritorna un riferimento all’oggetto remoto Registry su host e alla porta 1099

• getRegistry(String host, int port) ritorna un riferimento all’oggetto remoto Registry su host e alla porta port

Page 20: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata
Page 21: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

Il registro

• Il registro è anch’esso un oggetto remoto• Il metodo bind() appartiene all’interfaccia remota

implementata dal registro, • I parametri della chiamata dovranno essere

serializzati/deserializzati

Page 22: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

Warehouse Client

• Lato client possiamo ottenere un riferimento allo stub purché– Il registro sia online– L’oggetto remoto sia stato già pubblicato dal server

• Notare il cast a WarehouseI– Perché non usiamo Warehouse?– Client e Server hanno in comune solo l’interfaccia

remota WarehouseI– Il client non sa nemmeno cosa sia Warehouse

Page 23: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

Codice

public class WarehouseClient {public static void main(String[] args)throws NamingException, RemoteException, NotBoundException {Registry registry= LocateRegistry.getRegistry();System.out.print("RMI registry bindings: ");String[] e = registry.list();

for (int i=0; i<e.length; i++)System.out.println(e[i]);

String remoteObjectName = "centralWarehouse";WarehouseI centralWarehouse = (WarehouseI) registry.lookup(remoteObjectName);String descr = "Blackwell Toaster";double price = centralWarehouse.getPrice(descr);System.out.println(descr + ": " + price);

}}

Page 24: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

Esecuzione

Page 25: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

Registry (tecnicamente) remoto

Page 26: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

RMIInterface.java

public interface RMIInterface extends Remote {public String helloTo(String name) throws RemoteException;

}

Page 27: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

ServerOperation.javapublic class ServerOperation extends UnicastRemoteObject implements RMIInterface {private static final long serialVersionUID = 1L;

protected ServerOperation() throws RemoteException {super();

}@Overridepublic String helloTo(String name) throws RemoteException{

System.err.println(name + " is trying to contact!");return "Server says hello to " + name;

}

public static void main(String[] args){try {

Naming.rebind("//localhost/MyServer", new ServerOperation()); System.err.println("Server ready");

} catch (Exception e) {System.err.println("Server exception: " + e.toString());e.printStackTrace();

}}

}

Page 28: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

ClientOperation.java

public class ClientOperation {

private static RMIInterface lookUp;

public static void main(String[] args)throws MalformedURLException, RemoteException, NotBoundException {

lookUp = (RMIInterface) Naming.lookup("//localhost/MyServer");Scanner in = new Scanner(System.in);System.out.println("What is your name?");String txt = in.nextLine();in.close();

String response = lookUp.helloTo(txt);System.out.println(response);

}}

Page 29: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

rmiregistry

Page 30: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

Esecuzione

Page 31: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

Passaggio di oggetti

• Un oggetto non-remoto, passato come parametro, o restituito come risultato da un metodo remoto, è sempre passato per copia– Ovvero serializzato, scritto nello stream, e ricaricato

all’altro estremo dello stream, ma come un oggetto differente

– Modificare quindi un oggetto ricevuto mediante invocazione remota non ha alcun effetto sull’istanza originale di chi l’ha inviato

• Un oggetto remoto, già esportato, passato come parametro, o restituito come risultato da un metodo remoto è passato mediante il suo stub– Un oggetto remoto passato come parametro può solo

implementare interfacce remote

Page 32: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

Referential Integrity

• Se due riferimenti ad un oggetto sono passati da una JVM ad un’altra utilizzando una singola chiamata remota, questi riferimenti punteranno allo stesso oggetto anche nella JVM ricevente

• All’interno di una stessa chiamata remota il sistema RMI mantiene la referential integrity tra gli oggetti passati come parametro o come valori di ritorno

Page 33: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

Concorrenza

• La specifica RMI prevede che il server possa eseguire le invocazioni dei metodi remoti in modalità multi-threaded– I metodi esposti a chiamate remote devono essere

thread-safe– Gestire la concorrenza è a carico del programmatore

Page 34: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

Dynamic Class Loading

• Mediante il Dynamic Class Loading in Java è possibile caricare a runtime la definizione di classi Java

• Questa caratteristica è usata da RMI – Il client può ricevere da parte del server delle classi

sconosciute per le quali è necessario scaricare la definizione corrispondente (file .class)

Page 35: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

Warehouse evoluto

• Vogliamo modificare il nostro progetto Warehouse affinché cerchi un determinato prodotto sul server sulla base di una lista di keyword e non più semplicemente grazie alla descrizione del prodotto

• Vogliamo anche usare il dynamic class loading

Page 36: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

WarehouseI

public interface WarehouseI extends Remote {double getPrice(String description) throws RemoteException;Product getProduct(List<String> keywords) throws RemoteException;

}

Page 37: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

Dynamic Class Loading

• Il nostro server torna dei prodotti sulla base delle keyword che ha inviato il client

• Tuttavia se il prodotto non è presente si è deciso di tornare un oggetto di backup– in questo caso un oggetto di tipo Book che estende

Product

• Ma il client non ha idea di cosa sia un Book – Book non è stato inserito tra le dipendenze del Client – Quando abbiamo compilato il client Book non era

richiesto (vedi la struttura del progetto)

Page 38: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

Dynamic Class Loading

• Il server comunica l’URL della codebase al client• Il client contatta quindi il server http e scarica il

file Book.class in modo da poter eseguire il suo codice

• Il Dynamic Class Loading richiede la definizione di alcune policy di sicurezza

• Non approfondiremo la scrittura di una policy

Page 39: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

Struttura progetto

Page 40: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

server.policy

grant codeBase "file:/-" {permission java.security.AllPermission;

};

Page 41: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

Product

public class Product implements Serializable {private static final long serialVersionUID = 1L;

private String description;private double price;private WarehouseI location;

public Product(String description, double price) {this.description = description;this.price = price;

}public String getDescription() {return description;

}public double getPrice(){return price;

}public WarehouseI getLocation() {return location;

}public void setLocation(WarehouseI location) {this.location = location;

}}

Page 42: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

Book

public class Book extends Product {private static final long serialVersionUID = 1L;private String isbn;

public Book(String title, String isbn, double price) {super(title, price);this.isbn = isbn;

}

public String getDescription() {return super.getDescription() + " " + isbn;

}}

Page 43: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

Warehouse

public class Warehouse extends UnicastRemoteObject implements WarehouseI {private static final long serialVersionUID = 1L;

private Map<String, Product> products;private Product backup;

public Warehouse(Product backup) throws RemoteException {products = new HashMap<String, Product>();this.backup = backup;

}public void add(String keyword, Product product){

product.setLocation(this);products.put(keyword, product);

}public double getPrice(String description) throws RemoteException {for (Product p : products.values())if (p.getDescription().equals(description)) return p.getPrice();

if (backup == null) return 0;else return backup.getPrice();

}public Product getProduct(List<String> keywords) throws RemoteException {for (String keyword : keywords) {

Product p = products.get(keyword);if (p != null) return p;

}return backup;

}}

Page 44: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

WarehouseServer

public class WarehouseServer{public static void main(String[] args) throws RemoteException, NamingException{

System.setProperty("java.security.policy", "file:./server/server.policy");System.setSecurityManager(new SecurityManager());

System.out.println("Constructing server implementation");Warehouse centralWarehouse = new Warehouse(new Book("book", "123456", 66.99));centralWarehouse.add("toaster", new Product("Blackwell Toaster", 23.95));

try {System.out.println("Binding server impl. to registry");Registry registry= LocateRegistry.createRegistry(1099);registry.bind("centralWarehouse", centralWarehouse);

}catch (Exception e) {

System.err.println("WarehouseServer exception");e.printStackTrace();

}System.out.println("Waiting for clients");

}}

Page 45: RMI Remote Method Invocation - Luciano Baresi · 2020. 10. 27. · Verso RMI •Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegua una normale chiamata

WarehouseClient

public class WarehouseClient {public static void main(String[] args)throws NamingException, RemoteException, NotBoundException {

System.setProperty("java.security.policy", "file:./client/client.policy");System.setSecurityManager(new SecurityManager());

Registry registry= LocateRegistry.getRegistry();System.out.print("RMI registry bindings: ");String[] e = registry.list();

for (int i=0; i<e.length; i++)System.out.println(e[i]);

String remoteObjectName = "centralWarehouse";WarehouseI centralWarehouse = (WarehouseI) registry.lookup(remoteObjectName);

ArrayList<String> l=new ArrayList<String>();l.add("milk");Product p=centralWarehouse.getProduct(l);System.out.println("Description: " + p.getDescription());

}}