Programmazione distribuita in Java. da materiale di Carlo Ghezzi e Alfredo Mo:a



Documenti analoghi
Programmazione di rete in Java

Programmazione distribuita in Java. da materiale di Carlo Ghezzi e Alfredo Motta

Socket & RMI Ingegneria del Software - San Pietro

Programmazione distribuita in Java. da materiale di Carlo Ghezzi e Alfredo Motta

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

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

RMI. Java RMI RMI. G. Prencipe

Programmazione distribuita

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

(VHUFLWD]LRQLGLEDVHVXOOH6RFNHWLQ-DYD 6RFNHWGLWLSRVWUHDP

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

RMI Remote Method Invocation

Programmazione di sistemi distribuiti

Chat. Si ha un server in ascolto sulla porta Quando un client richiede la connessione, il server risponde con: Connessione accettata.

UnicastRemoteObject. Massimo Merro Programmazione di Rete 103 / 124

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

RMI: metodi equals e hashcode

Architettura Client-Server

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

Corso di Reti di Calcolatori L-A

Java Remote Method Invocation

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

Esercitazione di Sistemi Distribuiti: Java RMI

Telematica II 17. Esercitazione/Laboratorio 6

Parte II: Reti di calcolatori Lezione 10

Servizi Remoti. Servizi Remoti. TeamPortal Servizi Remoti

Remote Method Invocation (RMI)

Registratori di Cassa

Java e Serializzazione dalla A all'xml di Leonardo Puleggi

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

Programmazione a Oggetti Lezione 10. Ereditarieta

Java: Compilatore e Interprete

Laboratorio di Sistemi Distribuiti Leonardo Mariani

1. RETI INFORMATICHE CORSO DI LAUREA IN INGEGNERIA INFORMATICA SPECIFICHE DI PROGETTO A.A. 2013/ Lato client

19. LA PROGRAMMAZIONE LATO SERVER

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:

Introduzione alle applicazioni di rete

JNDI. Massimo Merro Programmazione di Rete 214 / 229

Parte II: Reti di calcolatori Lezione 12

20 - Input/Output su File

LABORATORIO DI INFORMATICA parte 6 -

Programmare in Java. Olga Scotti

GESTIONE DEI PROCESSI

Tecnologie Web L-A. Java e HTTP. Dario Bottazzi Tel , dario.bottazzi@unibo.it, SkypeID: dariobottazzi. Java e TCP/IP in a Nutshell

(VHUFLWD]LRQLGLEDVHVXOOH6RFNHWLQ-DYD 6RFNHWGLWLSRGDWDJUDP

Introduzione a Java Remote Method Invocation (RMI)

La prima applicazione Java. Creazione di oggetti - 1. La prima applicazione Java: schema di esecuzione. Gianpaolo Cugola - Sistemi Informativi in Rete

Programmazione dei socket con TCP #2

FPf per Windows 3.1. Guida all uso

Reti di Telecomunicazione Lezione 8

Luca Mari, Sistemi informativi applicati (reti di calcolatori) appunti delle lezioni. Architetture client/server: applicazioni server

Per chi ha la Virtual Machine: avviare Grass da terminale, andando su Applicazioni Accessori Terminale e scrivere grass

Il client deve stampare tutti gli eventuali errori che si possono verificare durante l esecuzione.

DESIGN PATTERNS Parte 6. State Proxy

Università degli Studi di Modena e Reggio Emilia. Facoltà di Ingegneria Reggio Emilia CORSO DI TECNOLOGIE E APPLICAZIONI WEB. Http con java, URL

progecad NLM Guida all uso Rel. 10.2

Ingegneria del Software. Presentazione del pattern Proxy

Prova Finale a.a. 2011/2012. Laboratorio 1: Introduzione a Java e Eclipse

Corso Eclipse. Prerequisiti. 1 Introduzione

Appunti di Informatica 1

Tale attività non è descritta in questa dispensa

Introduzione. Installare EMAS Logo Generator

Cenni di programmazione distribuita in C++ Mauro Piccolo

Corso di Reti di Calcolatori

1) GESTIONE DELLE POSTAZIONI REMOTE

MANUALE PARCELLA FACILE PLUS INDICE

Modulo. Programmiamo in Pascal. Unità didattiche COSA IMPAREREMO...

appunti delle lezioni Architetture client/server: applicazioni server

Programmare con le Socket TCP in java. 2: Application Layer 1

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

Manuale per la configurazione di AziendaSoft in rete

Istruzioni per l installazione del software per gli esami ICoNExam (Aggiornate al 15/01/2014)

Manuale Utente MyFastPage

FOXWave Gestione gare ARDF IZ1FAL Secco Marco Sezione ARI BIELLA

GUIDA ALLA PROGRAMMAZIONE GRAFICA IN C

Client - Server. Client Web: il BROWSER

appunti delle lezioni Architetture client/server: applicazioni client

Servers Activatable. Massimo Merro Programmazione di Rete 166 / 193

2 Fortino Lugi. Figura Errore. Nel documento non esiste testo dello stile specificato Finestra attiva o nuovo documento

Applicazioni distribuite

Mac Application Manager 1.3 (SOLO PER TIGER)

Programmare con le Socket

GESGOLF SMS ONLINE. Manuale per l utente

Configuration Managment Configurare EC2 su AWS. Tutorial. Configuration Managment. Configurare il servizio EC2 su AWS. Pagina 1

Compute engine generici in RMI

Il web server Apache Lezione n. 3. Introduzione

INDICE. Accesso al Portale Pag. 2. Nuovo preventivo - Ricerca articoli. Pag. 4. Nuovo preventivo Ordine. Pag. 6. Modificare il preventivo. Pag.

Invio SMS. DM Board ICS Invio SMS

La VPN con il FRITZ!Box - parte II. La VPN con il FRITZ!Box Parte II

Console di Amministrazione Centralizzata Guida Rapida

Corsi di Reti di Calcolatori (Docente Luca Becchetti)

A tal fine il presente documento si compone di tre distinte sezioni:

Corso di Reti di Calcolatori. Datagrammi

Java RMI (Remote Method Invocation)

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

I file di dati. Unità didattica D1 1

Reti di Telecomunicazione Lezione 6

Licenza per sito Manuale dell amministratore

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

Il calendario di Windows Vista

Transcript:

Programmazione distribuita in Java da materiale di Carlo Ghezzi e Alfredo Mo:a

Obie<vo Poter allocare computazioni su nodi fisici diversi e consen@re il coordinamento tra le computazioni sui diversi nodi

Nodi fisici e nodi logici Occorre dis@nguere tra nodi fisici e logici Può essere opportuno proge:are ignorando all inizio il nodo fisico in cui un nodo logico sarà allocato Java consente addiri:ura di vedere tu:o a:raverso la nozione di ogge< e di invocazione di metodi, dove l invocazione può essere remota

Archite:ura client- server È il modo classico di proge:are applicazioni distribuite su rete Server offre un servizio centralizzato a:ende che altri (client) lo conta<no per fornire il proprio servizio Client si rivolge ad apposito/i server per o:enere cer@ servizi

Middleware Per programmare un sistema distribuito vengono forni@ servizi (di sistema) specifici, come estensione del sistema opera@vo Il middleware viene posto tra il sistema opera@vo e le applicazioni In Java il middleware fa parte del linguaggio, diversamente da altri middleware (es. CORBA)

Middleware

Socket in Java Client e server comunicano (pacche< TCP) a:raverso socket Package java.net, classi: Socket, ServerSocket DatagramSocket (UDP): non considera@ in questo corso socket client socket server Endpoint individua@ da: indirizzo IP numero di porta

Socket (dal tutorial Java) A socket is one endpoint of a two- way communica@on link between two programs running on the network A socket is bound to a port number so that the TCP layer can iden@fy the applica@on that data is des@ned to be sent to

Comunicazione client- server 2 1 3

A:esa connessione (lato server) Creare un istanza della classe java.net.serversocket specificando il numero di porta su cui rimanere in ascolto ServerSocket sc = new ServerSocket(4567); Chiamare il metodo accept() che fa in modo che il server rimanga in ascolto di una richiesta di connessione (la porta non deve essere già in uso) Socket s = sc.accept(); Quando il metodo completa la sua esecuzione la connessione col client è stabilita e viene res@tuita un istanza di java.net.socket connessa al client remoto

Aprire connessione (lato client) Aprire un socket specificando l indirizzo IP e numero di porta del server Socket sc = new Socket( 127.0.0.1, 4567); Il numero di porta è compreso fra 1 e 65535 Le porte inferiori a 1024 sono riservate a servizi standard All indirizzo e numero di porta specifica@ ci deve essere in ascolto un processo server Socket ss = serversocket.accept(); Se la connessione ha successo si usano (sia dal lato client che dal lato server) gli stream associa@ al socket per perme:ere la comunicazione tra client e server (e viceversa) Scanner in = new Scanner(sc.getInputStream()); PrintWriter out = new PrintWriter(sc.getOutputStream());

Chiusura connessioni Per chiudere un ServerSocket o un Socket si u@lizza il metodo close() Per ServerSocket, close() fa terminare la accept() con IOExcep@on Per Socket, close() fa terminare le operazioni di le:ura o scri:ura del socket con eccezioni che dipendono dal @po di reader/writer u@lizzato Sia ServerSocket sia Socket hanno un metodo isclosed() che res@tuisce vero se il socket è stato chiuso

EchoServer Si crei un server che acce:a connessioni TCP sulla porta 1337 Una volta acce:ata la connessione il server leggerà ciò che viene scri:o una riga alla volta e ripeterà nella stessa connessione ciò che è stato scri:o Se il server riceve una riga quit chiuderà la connessione e terminerà l esecuzione

EchoServer public class EchoServer { private int port; private ServerSocket serversocket; public EchoServer(int port) { this.port = port; public static void main(string[] args) { EchoServer server = new EchoServer(1337); try { server.startserver(); catch (IOException e) { System.err.println(e.getMessage());

public void startserver() throws IOException { // apro una porta TCP serversocket = new ServerSocket(port); System.out.println("Server socket ready on port: " + port); // resto in attesa di una connessione Socket socket = serversocket.accept(); System.out.println("Received client connection"); // apro gli stream di input e output per leggere e scrivere // nella connessione appena ricevuta Scanner in = new Scanner(socket.getInputStream()); PrintWriter out = new PrintWriter(socket.getOutputStream()); // leggo e scrivo nella connessione finche' non ricevo "quit" while (true) { String line = in.nextline(); if (line.equals("quit")) { break; else { out.println("received: " + line); out.flush(); // chiudo gli stream e il socket System.out.println("Closing sockets"); in.close(); out.close(); socket.close(); serversocket.close(); E fondatamentale richiamare flush() per assicurarsi di scaricare il buffer (il suo contenuto verrà effe<vamente spedito al des@natario)

LineClient Si crei un client che si colleghi, con protocollo TCP, alla porta 1337 dell indirizzo IP 127.0.0.1 Una volta stabilita la connessione il client legge una riga alla volta dallo standard input e invia il testo digitato al server Il client inoltre stampa sullo standard output le risposte o:enute dal server Il client deve terminare quando il server chiude la connessione

LineClient public class LineClient { private String ip; private int port; public LineClient(String ip, int port) { this.ip = ip; this.port = port; public static void main(string[] args) { LineClient client = new LineClient("127.0.0.1", 1337); try { client.startclient(); catch (IOException e) { System.err.println(e.getMessage());

public void startclient() throws IOException { Socket socket = new Socket(ip, port); System.out.println("Connection established"); Scanner socketin = new Scanner(socket.getInputStream()); PrintWriter socketout = new PrintWriter(socket.getOutputStream()); Scanner stdin = new Scanner(System.in); try { while (true) { String inputline = stdin.nextline(); socketout.println(inputline); socketout.flush(); String socketline = socketin.nextline(); System.out.println(socketLine); catch(nosuchelementexception e) { System.out.println("Connection closed"); finally { stdin.close(); socketin.close(); socketout.close(); socket.close();

Archite:ura del server Il server che abbiamo visto acce:a una sola connessione (da un solo client) Un server dovrebbe essere in grado di acce:are connessioni da diversi client e di dialogare con ques@ contemporaneamente Idea: server mul@- thread All interno del processo Server far eseguire l istruzione accept() in un nuovo thread In questo modo è possibile acce:are più client contemporaneamente

EchoServer mul@- thread Spos@amo la logica che ges@sce la comunicazione con il client in una nuova classe ClientHandler che implementa Runnable La classe principale del server si occupa solo di istanziare il ServerSocket, eseguire la accept() e di creare i thread necessari per ges@re le connessioni acce:ate La classe ClientHandler si occupa di ges@re la comunicazione con il client associato al socket assegnato

public class MultiEchoServer { private int port; public MultiEchoServer(int port) { this.port = port; public void startserver() { ExecutorService executor = Executors.newCachedThreadPool(); ServerSocket serversocket; try { serversocket = new ServerSocket(port); catch (IOException e) { System.err.println(e.getMessage()); // porta non disponibile return; System.out.println("Server ready"); while (true) { try { Socket socket = serversocket.accept(); executor.submit(new EchoServerClientHandler(socket)); catch(ioexception e) { break; // entrerei qui se serversocket venisse chiuso executor.shutdown(); public static void main(string[] args) { MultiEchoServer echoserver = new MultiEchoServer(1337); echoserver.startserver(); EchoServer mul@- thread

public class EchoServerClientHandler implements Runnable { private Socket socket; public EchoServerClientHandler(Socket socket) { this.socket = socket; public void run() { try { Scanner in = new Scanner(socket.getInputStream()); PrintWriter out = new PrintWriter(socket.getOutputStream()); // leggo e scrivo nella connessione finche' non ricevo "quit" while (true) { String line = in.nextline(); if (line.equals("quit")) { break; else { out.println("received: " + line); out.flush(); // chiudo gli stream e il socket in.close(); out.close(); socket.close(); catch (IOException e) { System.err.println(e.getMessage()); EchoServer mul@- thread

Serializzazione

Le basi della serializzazione La serializzazione è un processo che trasforma un ogge:o in memoria in uno stream di byte La de- serializzazione è il processo inverso Ricostruisce un ogge:o Java da uno stream di byte e lo riporta nello stesso stato nel quale si trovava quando è stato serializzato 01001001011 00110

Le basi della serializzazione Solo le istanze delle classi possono essere serializzate I @pi primi@vi non possono essere serializza@ Affinché sia possibile serializzare un ogge:o, la sua classe o una delle sue superclassi deve implementare l interfaccia Serializable L interfaccia Serializable è un interfaccia vuota u@lizzata solo come metodo per marcare un ogge:o che può essere serializzato Per serializzare/de- serializzare un ogge:o basta scriverlo dentro un ObjectOutputStream/ObjectInputStream Per scrivere/leggere i @pi primi@vi u@lizzare i metodi della DataOutput/DataInput interface implementa@ da ObjectOutputStream/ObjectInputStream

Serializzazione Le basi della serializzazione FileOutputStream out = new FileOutputStream( save.ser ); ObjectOutputStream oos = new ObjectOutputStream( out ); oos.writeobject( new Date() ); oos.close(); De-Serializzazione FileInputStream in = new FileInputStream( save.ser ); ObjectInputStream ois = new ObjectInputStream( in ); Date d = (Date) ois.readobject(); ois.close();

Metodo di encoding Il metodo di encoding standard di Java Traduce i campi dell ogge:o in uno stream di byte Tipi primi@vi Ogge< non- transient e non- sta@c Per ques@ ul@mi si applica lo stesso processo di serializzazione non-transient obj2 transient obj3 serializable obj1 not serializable non-transient obj3

Metodo di encoding La serializzazione fallisce se almeno uno degli ogge< appartenen@ al grafo dei riferimen@ non- transient non è serializzabile E possibile intervenire su questo comportamento ridefinendo cer@ campi come transient oppure ridefinendo la procedura di serializzazione per un determinato @po di ogge:o non-transient obj2 non-transient obj3 serializable obj1 not serializable non-transient obj3

Metodo di encoding Dato un OutputStream e un insieme di ogge< che devono essere serializza@ Java assegna un iden@fica@vo univoco ad ogni ogge:o Se l ogge:o è già stato serializzato (perché presente come riferimento in uno degli ogge< preceden@) non viene serializzato nuovamente Nell esempio che segue salvando obj1 e obj2 su uno stesso stream, obj3 verrà serializzato una sola volta Ma se serializziamo obj1 e obj2 su due stream diversi, allora quando leggeremo ci ritroveremo con due istanze diverse di obj3 obj1 obj2 obj1 obj2 obj3 obj3 obj3 bis

Serializzazione ed ereditarietà Se una classe serializzabile C ha una super- classe non- serializzabile S, le istanze di C possono comunque essere serializzate se S ha un costru:ore vuoto accessibile dalla so:oclasse Il costru:ore senza argomen@ di S viene invocato automa@camente durante la deserializzazione di C in modo da costruire la parte rela@va ad S nell ogge:o che s@amo deserializzando

Personalizzare la serializzazione Il processo di serializzazione e di deserializzazione può essere personalizzato in due modi: Implementando i metodi writeobject(objectoutputstream oos) e readobject(objectinputstream ois) devono essere dichiara@ come private verranno invoca@ da ObjectOutputStream e ObjectInputStream durante il processo di serializzazione/ deserializzazione mediante reflec@on Implementando l interfaccia Externalizable E quindi i metodi readexternal(objectinput in) e writeexternal(objectoutput out) per leggere e scrivere il proprio stato da/su uno stream

Esempio class SessionDTO implements Serializable { private static final long serialversionuid = 1L; private transient int data; // Stores session data //Session activation time (creation, deserialization) private transient long activationtime; public SessionDTO(int data) { this.data = data; this.activationtime = System.currentTimeMillis(); private void writeobject(objectoutputstream oos) throws IOException { oos.defaultwriteobject(); oos.writeint(data); System.out.println("session serialized"); private void readobject(objectinputstream ois) throws IOException, ClassNotFoundException { ois.defaultreadobject(); data = ois.readint(); activationtime = System.currentTimeMillis(); System.out.println("session deserialized"); public int getdata() { return data; public long getactivationtime() { return activationtime;

RMI Remote Method Invoca@on da materiale di Carlo Ghezzi e Alfredo Mo:a

L idea alla base di tu:a la programmazione distribuita è semplice Un client esegue una determinata richiesta Tale richiesta viaggia lungo la rete verso un determinato server des@natario Il server processa la richiesta e manda indietro la risposta al client per essere analizzata Con i socket però dobbiamo ges@re personalmente il formato dei messaggi e la ges@one della connessione Verso RMI

Verso RMI Quello che cerchiamo è un meccanismo con il quale il programmatore del client esegue 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 ogge:o ma maschera tu:o il processo di u@lizzo della rete per eseguire il metodo sul server Allo stesso modo il programmatore che implementa il servizio non vuole preoccuparsi della ges@one della comunicazione con il client e per questo installa anche lui un proxy sul server Il proxy del server comunica con il proxy del client creando un livello di astrazione al programmatore che non vede la rete

Verso RMI

Le basi di RMI Ogge:o remoto Ogge:o i cui metodi possono essere invoca@ da una Java Virtual Machine diversa da quella in cui l ogge:o risiede Interfaccia Remota Interfaccia che dichiara quali sono i metodi che possono essere invoca@ da una diversa Java Virtual Machine Server Insieme di uno o più ogge< remo@ che, implementando una o più interfacce remote, offrono delle risorse (da@ e/o procedure) a macchine esterne distribuite sulla rete Remote Method Invoca@on (RMI) Invocazione di un metodo presente in una interfaccia remota implementata da un ogge:o remoto La sintassi di una invocazione remota è iden@ca a quella locale

Archite:ura interna Il client colloquia con un proxy locale del server, de:o stub lo stub rappresenta il server sul lato client implementa l'interfaccia del server è capace di fare forward di chiamate di metodi il client ha un riferimento locale all ogge:o stub Esiste anche un proxy del client sul lato server, de:o skeleton è una rappresentazione del client chiama i servizi del server sa come fare forward dei risulta@ lo skeleton ha un riferimento all'ogge:o

Archite:ura interna

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 ogge:o remoto Il client potrà quindi o:enere lo stub u@lizzando il nome che gli è stato assegnato

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 differen@ è necessario u@lizzare un server HTTP per perme:ere al registro di spedire lo stub

Riassumendo Lato client Viene richiesto a un registro RMI lo stub per l invocazione di un determinato ogge:o remoto I parametri in ingresso all invocazione remota vengono serializza@ (tale processo è chiamato marshalling) L invocazione remota viene inviata al server Lato server Il server localizza l ogge:o remoto che deve essere invocato Chiama il metodo desiderato passandogli i parametri ricevu@ dal client Ca:ura il valore di ritorno o le eventuali eccezioni Spedisce allo stub del client un pacche:o contenente i da@ ritorna@ dal metodo

Running Example Vogliamo realizzare un applicazione che ges@sce un magazzino (Warehouse) Il magazzino con@ene un insieme di prodo< e ogni prodo:o è iden@ficato da: Una stringa che iden@fica il prodo:o Un prezzo

Interfaccia condivisa client- server L ogge:o remoto Warehouse definisce l interfaccia tra client e server Estende la Remote interface di Java Richiede la ges@one di eventuali RemoteExcep@on nel caso in cui ci fossero errori di rete

Interfaccia condivisa client- server import java.rmi.*; Interfaccia condivisa dal client e dal server. Entrambi sanno che si tra:a di un interfaccia remota public interface Warehouse extends Remote { double getprice(string description) throws RemoteException; I client saranno costre< a ges@re gli errori che possono sorgere durante l invocazione di un ogge:o remoto

Warehouse Server Il server implementa l interfaccia remota Estende la classe UnicastRemoteObject che rende l ogge:o accessibile da remoto

import java.rmi.*; import java.rmi.server.*; import java.util.*; Warehouse Server public class WarehouseImpl extends UnicastRemoteObject implements Warehouse { private Map<String, Double> prices; public WarehouseImpl() throws RemoteException { prices = new HashMap<String, Double>(); prices.put("blackwell Toaster", 24.95); prices.put("zapxpress Microwave Oven", 49.95); Rende l ogge:o accessibile da remoto public double getprice(string description) throws RemoteException { Double price = prices.get(description); return price == null? 0 : price; Definisco l implementazione lato server dell interfaccia definita precedentemente

Warehouse Server (Alterna@va) import java.rmi.*; import java.rmi.server.*; import java.util.*; Definisco l implementazione lato server dell interfaccia definita precedentemente public class WarehouseImpl implements Warehouse { public WarehouseImpl() throws RemoteException { prices = new HashMap<String, Double>(); prices.put("blackwell Toaster", 24.95); prices.put("zapxpress Microwave Oven", 49.95); UnicastRemoteObject.exportObject(this, 0); Rende l ogge:o accessibile da remoto (soluzione alterna@va) public double getprice(string description) throws RemoteException { Double price = prices.get(description); return price == null? 0 : price; private Map<String, Double> prices;

Pubblicare l ogge:o remoto (1) All avvio il server pubblica sul registro RMI l ogge:o remoto In questo modo il client potrà cercare gli ogge< remo@ disponibili e o:enere un riferimento Il registro RMI deve essere online prima di avviare il server (vedremo come lanciarlo) Di default il registro si trova in localhost sulla porta 1099 WarehouseImpl centralwarehouse = new WarehouseImpl(); Registry registry = LocateRegistry.getRegistry(); registry.bind("central_warehouse", centralwarehouse); S@amo facendo un binding tra il nome central_warehouse e l ogge:o remoto centralwarehouse

Pubblicare l ogge:o remoto (2) import java.rmi.*; import javax.naming.*; public class WarehouseServer { public static void main(string[] args) throws RemoteException, NamingException { System.out.println("Constructing server implementation..."); WarehouseImpl centralwarehouse = new WarehouseImpl(); System.out.println("Binding server implementation to registry..."); Registry registry= LocateRegistry.getRegistry(); registry.bind( central_warehouse", centralwarehouse); System.out.println("Waiting for invocations from clients...");

Note tecniche su bind() Per ragioni di sicurezza un applicazione può associare, deassociare o riassociare un ogge:o 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 fare un lookup degli ogge< String[] remoteobjects = registry.list();

Note tecniche sul registro Il registro è anch esso un ogge:o remoto Il metodo bind() appar@ene all interfaccia remota implementata dal registro, infa< void bind(string name, Remote obj) throws RemoteException, AlreadyBoundException, AccessException; I parametri della chiamata dovranno essere serializza@/deserializza@ Il registro scaricherà a run@me la definizione dell interfaccia remota (nel nostro caso Warehouse) per serializzare l ogge:o che gli s@amo passando

Warehouse Client Lato client possiamo o:enere un riferimento al nostro stub con questo codice, purché: Il registro sia online L ogge:o remoto sia stato già pubblicato dal server String remoteobjectname = "central_warehouse"; Warehouse centralwarehouse = (Warehouse) registry.lookup(remoteobjectname); Notare il cas@ng a Warehouse Perché non usiamo WarehouseImpl? Client e Server hanno in comune solo Warehouse, l interfaccia remota Il client non sa nemmeno cosa sia WarehouseImpl

Warehouse Client import java.rmi.*; import java.util.*; import javax.naming.*; public class WarehouseClient { public static void main(string[] args) throws NamingException, RemoteException { Registry registry= LocateRegistry.getRegistry(); System.out.print("RMI registry bindings: "); String[] e = registry.list(); for (int i=0; i<e.legth; i++) System.out.println(e[i]); String remoteobjectname = "central_warehouse"; Warehouse centralwarehouse = (Warehouse) registry.lookup(remoteobjectname); String descr = "Blackwell Toaster"; double price = centralwarehouse.getprice(descr); System.out.println(descr + ": " + price);

Deployare l applicazione RMI Cosa ci serve per far par@re il tu:o Avviamo il server HTTP per perme:ere al registro RMI di recuperare la definizione delle nostre interfacce remote Avviamo il registro RMI Per perme:ere al client di trovare gli ogge< remo@ pubblica@ dal nostro server Avviamo il server All avvio il server registrerà l ogge:o remoto Warehouse Il registro RMI scarica la definizione dell interfaccia remota dal server HTTP Avviamo il client Per vedere finalmente l output della nostra applicazione

Se<ngs (1) Sulla macchina server avremo server/ WarehouseServer.class WarehouseImpl.class download/ Warehouse.class Sulla macchina client avremo client/ WarehouseClient.class

Se<ngs (2) In fase di bind il registro RMI ha quindi bisogno di accedere alla definizione delle interfacce remote I file.class solitamente vengono distribui@ con un normale web server Nel nostro esempio il server deve rendere disponibile il file WareHouse.class Scarichiamo quindi NanoHTTPD web server Un mini- server web la cui implementazione è contenuta tu:a in NanoHTTPD.java Dopo aver compilato il server dovremmo trovarci nella seguente situazione download/ Warehouse.class NanoHTTPD.class

Avviamo l HTTP Server Avviamo il server HTTP in localhost sulla porta 8080 Per verificare che tu:o funzioni proviamo ad accedere all indirizzo h:p://localhost:8080 via browser Tale indirizzo verrà poi u@lizzato dal server per dichiarare la loca@on della codebase rmi property (vedi slide Avviamo il server) $ java download/nanohttpd 8080

Avviamo il registro RMI Su Linux e Osx $ rmiregistry Su Windows $ start rmiregistry In generale è necessario che l eseguibile rmiregistry sia presente nel nostro path rmiregistry viene distribuito con Java, lo trovate quindi nella sua cartella di installazione

Avviamo il Server Andiamo nella directory del server e digi@amo $ java WarehouseServer Cosa vediamo? Constructing server implementation... Binding server implementation to registry... Exception in thread "main" javax.naming.communicationexception [Root exception is java.rmi.serverexception: RemoteException occurred in server thread; nested exception is: java.rmi.unmarshalexception: error unmarshalling arguments; nested exception is: java.lang.classnotfoundexception: Warehouse] at com.sun.jndi.rmi.registry.registrycontext.bind(registrycontext.java:143) at com.sun.jndi.toolkit.url.genericurlcontext.bind(genericurlcontext.java:226) at javax.naming.initialcontext.bind(initialcontext.java:419) at WarehouseServer.main(WarehouseServer.java:13)

Avviamo il Server Andiamo nella directory del server e digi@amo $ java -Djava.rmi.server.codebase=http://localhost:8080/ WarehouseServer L opzione - Djava.rmi.server.codebase server a specificare l URL dove si trovano I file.class che servono al registro RMI Quando eseguite questo comando date un occhiata al terminale dove sta girando NanoHTTPD Vedrete un messaggio che fa vedere la richiesta del registro RMI interessato al file WareHouse.class

Nota tecnica Dopo aver avviato il server la console resta in esecuzione Se guardiamo il codice del server questo potrebbe sembrarci strano Il programma ha solo creato un ogge:o WarehouseImpl e l ha registrato sul RMI registry La spiegazione è che quando creiamo un ogge:o di @po UnicastRemoteObject viene creato un thread separato che @ene vivo il programma Questa funzione è necessaria per assolvere alla funzione di server

Avviamo il client Infine apriamo una quarta console, andiamo nella cartella contenente i file del client e digi@amo $ java WarehouseClient Questo completa la nostra prima applicazione RMI

Loggare la nostra applicazione Viste le immense difficoltà che un applicazione distribuita comporta può essere molto u@le loggare la nostra applicazione Nel caso più semplice basta avviare il server con l opzione Djava.rmi.server.logCalls=true Tu:e le chiamate RMI ed eventuali eccezioni verranno salvate in System.err

Server HTTP un alterna@va Se vogliamo deployare la nostra applicazione senza usare un server HTTP basta avviare il server con la seguente opzione Djava.rmi.server.codebase=file:/path/to/classDir/ Lo slash finale è importante Questa soluzione è o<male nei nostri ambien@ di test dove il registro RMI e il client risiedono effe<vamente sulla stessa macchina del server

Passaggio di ogge< Un ogge:o non- remoto (passato come parametro, o res@tuito come risultato da un metodo remoto) è passato per copia Ovvero serializzato, scri:o nello stream, e ricaricato all altro estremo dello stream, ma come ogge:o differente Modificare quindi un ogge:o ricevuto mediante invocazione remota non ha alcun effe:o sull istanza originale di chi l ha inviato Un ogge:o remoto (già esportato, passato come parametro, o res@tuito come risultato da un metodo remoto) è passato mediante il suo stub Ogge< remo@ non esporta@ non verranno sos@tui@ dal loro stub corrispondente Un ogge:o remoto passato come parametro può solo implementare interfacce remote

Referen@al Integrity Se due riferimen@ ad un ogge:o sono passa@ da una JVM ad un altra u@lizzando una singola chiamata remota, ques@ riferimen@ punteranno allo stesso ogge:o anche nella JVM ricevente All interno di una stessa chiamata remota il sistema RMI man@ene la referen@al integrity tra gli ogge< passa@ come parametro o come valori di ritorno obj1 obj2 Caso (1) remoteobject.remotemethodtwoparameters(obj1, obj2); obj3 Caso (2) remoteobject.remotemethodoneparameter(obj1); remoteobject.remotemethodoneparameter(obj2);

Concorrenza La specifica RMI prevede che il server possa eseguire le invocazioni dei metodi remo@ in modalità mul@- threaded I metodi espos@ a chiamate remote devono essere thread- safe Ges@re la concorrenza è a carico del programmatore

Dynamic Class Loading Mediante il Dynamic Class Loading in Java è possibile caricare a run@me la definizione di classi Java Questa cara:eris@ca è usata con RMI Il client può ricevere da parte del server delle classi sconosciute per le quali è necessario scaricare la definizione corrispondente (file.class) Vediamo con un esempio pra@co un caso d uso di questa tecnologia

Warehouse V2 Vogliamo modificare il nostro proge:o Warehouse affinché cerchi un determinato prodo:o sul server sulla base di una lista di keyword e non più semplicemente grazie alla descrizione del prodo:o Ecco l interfaccia remota aggiornata: import java.rmi.*; import java.util.*; public interface Warehouse extends Remote { double getprice(string description) throws RemoteException; Product getproduct(list<string> keywords) throws RemoteException;

Stru:ura proge:o Il proge:o è diviso in tre compila(on unit Server e Client dipendono entrambi dalla definizione delle interfacce condivise Warehouse è l interfaccia dell ogge:o remoto Product è richiesto da Warehouse server/ WarehouseServer.class WarehouseImpl.class Book.class <<dependency>> download/ Warehouse.class Product.class client/ WarehouseClient.class <<dependency>>

Workflow dell applicazione Il client u@lizzerà una lista di stringhe per cercare un prodo:o Il prodo:o ritornato avrà un riferimento remoto alla Warehouse

La classe Product import java.io.*; public class Product implements Serializable { private String description; private double price; private Warehouse location; public Product(String description, double price) { this.description = description; this.price = price; public String getdescription() { return description; public double getprice(){ return price; public Warehouse getlocation() { return location; public void setlocation(warehouse location) { this.location = location; Questa classe sarà presente sia sul client che sul server Stabilisce cosa è un prodo:o e che funzionalità offre Non è un ogge:o remoto ma è serializzabile Il server dovrà inviare i prodo< al client

La classe Book public class Book extends Product { public Book(String title, String isbn, double price) { super(title, price); this.isbn = isbn; public String getdescription() { return super.getdescription() + " " + isbn; private String isbn;

WarehouseImpl public class WarehouseImpl extends UnicastRemoteObject implements Warehouse { private Map<String, Product> products; private Product backup; public WarehouseImpl(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(description); public Product getproduct(list<string> keywords) throws RemoteException { for (String keyword : keywords){ Product p = products.get(keyword); if (p!= null) return p; return backup;

WarehouseServer import java.rmi.*; import javax.naming.*; public class WarehouseServer { public static void main(string[] args) throws RemoteException, NamingException { System.out.println("Constructing server implementation..."); WarehouseImpl centralwarehouse = new WarehouseImpl( new Book( BackupBook", 123456", 66.99)); centralwarehouse.add("toaster", new Product("Blackwell Toaster", 23.95)); System.out.println("Binding server implementation to registry..."); Registry registry= LocateRegistry.getRegistry(); registry.bind( central_warehouse", centralwarehouse); System.out.println("Waiting for invocations from clients...");

WarehouseClient import java.rmi.*; import java.util.*; import javax.naming.*; import java.util.arraylist; public class WarehouseClient { public static void main(string[] args) throws NamingException, RemoteException { Context namingcontext = new InitialContext(); System.setProperty("java.security.policy", "client.policy"); System.setSecurityManager(new SecurityManager()); System.out.print("RMI registry bindings: "); Enumeration<NameClassPair> e = namingcontext.list("rmi://localhost/"); while (e.hasmoreelements()) System.out.println(e.nextElement().getName()); String url = "rmi://localhost/central_warehouse"; Warehouse centralwarehouse = (Warehouse) namingcontext.lookup(url); ArrayList<String> l=new ArrayList<String>(); l.add("toaster"); Product p=centralwarehouse.getproduct(l); System.out.println("Description: " + p.getdescription()); A run@me possiamo ricevere un book! Ma come fa il client a conoscerlo? Book è stato compilato solamente sul server

Dynamic Class Loading Il nostro server torna dei prodo< sulla base delle keyword che ha inviato il client Tu:avia se il prodo:o non è presente si è deciso di tornare un ogge:o di backup in questo caso un ogge:o di @po 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 stru:ura del proge:o)

Dynamic Class Loading Il server comunica l URL della codebase al client Mediante l a:ributo java.rmi.server.codebase Il client conta:a quindi il server h:p e scarica il file Book.class in modo da poter eseguire il suo codice Tu:o questo avviene in maniera trasparente

Dynamic Class Loading e Security Policy Il Dynamic Class Loading richiede la definizione di alcune policy di sicurezza eseguire un file.class scaricato dall esterno non è sicuramente il massimo Non approfondiremo la scri:ura di una policy Tale policy va indicata nel codice sorgente di chi esegue il caricamento di classi a run@me

WarehouseClient import java.rmi.*; import java.util.*; import javax.naming.*; import java.util.arraylist; public class WarehouseClient { public static void main(string[] args) throws NamingException, RemoteException { Context namingcontext = new InitialContext(); System.setProperty("java.security.policy", "client.policy"); System.setSecurityManager(new SecurityManager()); System.out.print("RMI registry bindings: "); Enumeration<NameClassPair> e = namingcontext.list("rmi://localhost/"); while (e.hasmoreelements()) System.out.println(e.nextElement().getName()); String url = "rmi://localhost/central_warehouse"; Warehouse centralwarehouse = (Warehouse) namingcontext.lookup(url); ArrayList<String> l=new ArrayList<String>(); l.add("toaster"); Product p=centralwarehouse.getproduct(l); System.out.println("Description: " + p.getdescription());

import java.rmi.*; import javax.naming.*; WarehouseServer public class WarehouseServer{ public static void main(string[] args) throws RemoteException, NamingException { System.setProperty("java.security.policy", "server.policy"); System.setSecurityManager(new SecurityManager()); System.out.println("Constructing server implementation..."); WarehouseImpl centralwarehouse = new WarehouseImpl( new Book( BackupBook", 123456", 66.99)); centralwarehouse.add("toaster", new Product("Blackwell Toaster", 23.95)); System.out.println("Binding server implementation to registry..."); Context namingcontext = new InitialContext(); namingcontext.bind("rmi:central_warehouse", centralwarehouse); System.out.println("Waiting for invocations from clients...");