Scarano - Dipartimento di Informatica

"Programmazione Distribuita" - Prof.
Scarano
Laurea in Informatica
Organizzazione della lezione
• Oggetti attivabili
Vi.ttorio Scarano
– meccanismo e protocollo di attivazione
– esempi
– dati persistenti
Programmazione Distribuita.
16. Java Remote Method
Invocation (4)
Vittorio Scarano
Corso di Programmazione Distribuita
Laurea di I livello in Informatica
Università degli Studi di Salerno
2
Persistenza
Le classi ed interfacce di RMI
– insieme di numerosi oggetti che devono fornire servizi
Programmazione Distribuita.
• Alcune considerazioni:
Programmazione Distribuita.
Object
– è inutile avere attivi degli oggetti se non vengono utilizzati
– è possibile che ci siano dei problemi sulla macchina server
che obblighi a far “ripartire” il sistema
• ripristinando i dati relativi agli oggetti server
• A questo scopo sono introdotti in RMI gli oggetti
“Attivabili”
IOException
<<interface>>
Remote
Vi.ttorio Scarano
Vi.ttorio Scarano
• In generale, un sistema a oggetti distribuiti deve offrire
la persistenza dei dati
RemoteObject
RemoteException
RemoteServer
Activatable
UnicastRemoteObject
3
4
Attivazione di oggetti
Terminologia utilizzata
Vi.ttorio Scarano
– gestendo la loro esecuzione
– sulla base delle richieste pervenute
• Lazy activation
– un oggetto viene attivato solamente all’atto della prima
chiamata ricevuta
– inizializzandone lo stato
– e, se necessario, facendo partire una JVM appropriata
5
A.A. 2002-2003 Università di Salerno
• Un oggetto (distribuito) è attivose
Programmazione Distribuita.
Programmazione Distribuita.
Vi.ttorio Scarano
• E’ un meccanismo per fornire riferimenti persistenti ad
oggetti distribuiti
– risulta essere istanziato ed esportato (in esecuzione) su una
JVM
• Un oggetto (distribuito) è passivo se
– risulta non essere ancora istanziato ed in esecuzione, ma può
essere portato nello stato di attivo
• Il processo di trasformare un oggetto passivo in attivo è
detto attivazione
6
1
"Programmazione Distribuita" - Prof.
Scarano
Laurea in Informatica
La lazy activation
Protocollo di attivazione - 1
• Meccanismo di riferimento remoto faulting
• In caso il riferimento remoto sia null il riferimento
remoto faulting inizia un protocollo di attivazione
• Componenti
Vi.ttorio Scarano
Vi.ttorio Scarano
– alla prima invocazione su un metodo di un oggetto
– un identificatore di attivazione (activation identifier)
Programmazione Distribuita.
Programmazione Distribuita.
• Ogni riferimento remoto faulting contiene
• server per comunicare i dati per far attivare l’oggetto
– un riferimento remoto all’oggetto remoto
• all’inizio vale null poi contiene il riferimento dell’oggetto attivato
• Importante: anche in presenza di fallimenti hw/sw
– RMI garantisce la semantica sui metodi chiamata “at most
once”: il metodo non è mai eseguito più volte
• l’ attivatore
• il gruppo di attivazione
• l’oggetto remoto da attivare
• L’attivatore (uno per host)
– contiene un database di informazioni che associano
identificatori di attivazione alle informazioni necessarie per
la attivazione (classe, URL, dati per il bootstrap, etc)
– manager di JVM (una per gruppo)
7
8
Protocollo di attivazione - 2
Come creare un oggetto attivabile
• Il gruppo di attivazione (uno per ogni JVM)
• Necessario:
• Passi del protocollo:
• l’ attivatore usa le informazioni relative all’identificatore di
attivazione
• se esiste il gruppo di atttivazione, invia la richiesta al gruppo
• altrimenti, istanzia una JVM per il gruppo e poi invia la richiesta
• il gruppo carica la classe, istanzia l’oggetto (con un costruttore
particolare)
• ne restituisce il riferimento remoto all’ attivatore
• che lo registra e lo restituisce al riferimento remoto faulting
• che invia la richiesta di esecuzione di metodo all’oggetto
• Il descrittore di attivazione può essere registrato:
Programmazione Distribuita.
Programmazione Distribuita.
– registrare il descrittore di attivazione
– includere uno speciale costruttore usato per la attivazione
Vi.ttorio Scarano
Vi.ttorio Scarano
• riceve la richiesta di attivazione e restituisce il riferimento
all’oggetto attivato all’attivatore
• usando dei costruttori di Activatable
10
I costruttori di Activatable - 2
• 2 costruttori:
• Costruttori per istanziazione e attivazione
Vi.ttorio Scarano
• se si vuole istanziare un oggetto e contemporaneamente renderlo
attivabile
• può servire per permettere l’automatico restart dell’oggetto
– per la sola attivazione
• chiamato dall’ attivatore all’atto della prima invocazione
• Ognuno di questi costruttori ha una variante
– per l’utilizzo di socket personalizzati con una SocketFactory
• crittografia (SSL, etc.), protocolli particolari
11
Programmazione Distribuita.
Vi.ttorio Scarano
– per la instanziazione e registrazione
Programmazione Distribuita.
• se l’oggetto non deriva da Activatable
– all’atto della creazione (se si vuole istanziare comunque
l’oggetto senza una chiamata)
9
I costruttori di Activatable - 1
A.A. 2002-2003 Università di Salerno
– con il metodo register() (statico) di Activatable
– con il metodo exportObject() di Activatable
protected Activatable (String codebase,
java.rmi.MarshalledObject data,
boolean restart,
int port)
throws ActivationException, java.rmi.RemoteException;
protected Activatable (String codebase,
java.rmi.MarshalledObject data,
boolean restart,
int port,
RMIClientSocketFactory csf,
RMIServerSocketFactory ssf)
throws ActivationException, java.rmi.RemoteException;
12
2
"Programmazione Distribuita" - Prof.
Scarano
Laurea in Informatica
I costruttori di Activatable - 3
Il demon di attivazione: rmid
• Costruttori per la attivazione
• In carica del ruolo di attivatore
• Lanciato con
Vi.ttorio Scarano
protected Activatable (ActivationID id,
java.rmi.MarshalledObject data,
int port)
throws java.rmi.RemoteException;
protected Activatable (ActivationID id,
java.rmi.MarshalledObject data,
int port,
RMIClientSocketFactory csf,
RMIServerSocketFactory ssf)
throws java.rmi.RemoteException;
Programmazione Distribuita.
Programmazione Distribuita.
Vi.ttorio Scarano
– se la porta è zero viene usato una porta anonima
– rmid -J-Djava.security.policy=rmid.policy
– che permette il passaggio della security policy al demon
• Usa una directory log (modificabile da parametri) per
mantenere il database degli identificatori di attivazione
• Alcuni parametri utili:
-C per passare parametri ad ognuna delle JVM lanciate
ad esempio: rmid -C-Djava.rmi.server.logCalls=true
- stop per fermare il demon
13
14
Un esempio: ActRemoteHello
Il diagramma di ActRemoteHello
Vi.ttorio Scarano
– Hello: interfaccia remota
– HelloClient: client
– HelloImpl: oggetto attivabile
• deriva da Activatable
– SetupRemoteHello:
• registra l’oggetto HelloImpl (o meglio il suostub) all’ activator
(rmid) con le informazioni necessarie per permetterne la attivazione
Programmazione Distribuita.
Programmazione Distribuita.
Vi.ttorio Scarano
• Il solito servizio di saluto personalizzato
• Composto da:
15
16
• Unico metodo remoto
Vi.ttorio Scarano
– lancia una eccezione
remota
Programmazione Distribuita.
public interface Hello
extends java.rmi.Remote {
String dimmiQualcosa( String daChi )
throws java.rmi.RemoteException;
}
Il diagramma di ActRemoteHello
Programmazione Distribuita.
Vi.ttorio Scarano
La interface remote: Hello.java
17
A.A. 2002-2003 Università di Salerno
18
3
"Programmazione Distribuita" - Prof.
Scarano
Laurea in Informatica
• Estende Activatable
• Primo costruttore
Vi.ttorio Scarano
import java.rmi.*;
import java.rmi.activation.*;
public class HelloImpl extends Activatable
implements Hello {
// Costruttore per costr. regist. ed export
public HelloImpl( String codebase,
MarshalledObject data )
throws RemoteException,
ActivationException {
super( codebase , data, false, 0 );
System.out.println( "Primo costruttore" );
}
// Costruttore per attivazione ed esportazione
public HelloImpl( ActivationID id,
MarshalledObject data )
throws RemoteException {
super( id, 0 );
System.out.println( "Secondo costruttore" );
} // continua….
La implementazione: HelloImpl.java (2)
– solo per istanziare e
attivare (non usato)
• Secondo costruttore
– fornito per permettere
la attivazione a rmid
in caso di chiamata di
metodi remoti
Programmazione Distribuita.
Programmazione Distribuita.
Vi.ttorio Scarano
La implementazione: HelloImpl.java (1)
Vi.ttorio Scarano
Vi.ttorio Scarano
Programmazione Distribuita.
Programmazione Distribuita.
}
}
– restituisce lo stub
– … di cui va fatto il bind
su rmiregistry
23
A.A. 2002-2003 Università di Salerno
• Set SM
• Proprietà delle JVM
lanciate da rmid
– solo per test: policyall
• Creazione del gruppo
– descrittore
– group ID dalla
registrazione
22
Il diagramma di ActRemoteHello
Vi.ttorio Scarano
• URL per la posizione
dello stub
• Dati da passare alla
classe
• Creazione del descrittore
di attivazione
• Registrazione
sull’activator del
descrittore di attivazione
import java.rmi.*;
import java.rmi.activation.*;
import java.util.Properties;
public class SetupRemoteHello {
public static void main( String args[] ) {
System.setSecurityManager( new
RMISecurityManager() );
String home = "/ProgettiJava/ ActRemoteHello";
try {
Properties props = new Properties ();
props.put("java.security.policy", home+"/policyall");
ActivationGroupDesc.CommandEnvironment
ace = null ;
ActivationGroupDesc helloGroup = new
ActivationGroupDesc (props, ace);
ActivationGroupID agi =
ActivationGroup.getSystem().registerGroup(
helloGroup);
// continua…
Programmazione Distribuita.
Vi.ttorio Scarano
Programmazione Distribuita.
Hello hi = (Hello)Activatable.register(desc);
System.out.println("Ho lo stub per HelloImpl");
Naming.rebind ("RemoteHello", hi);
System.out.println(".. e lo esporto sul registry");
} catch ( Exception e ) {
e.printStackTrace();
}
System.out.println("Salute a tutti!");
System.exit(0);
}
// end classe HelloImpl
La registrazione:SetupRemoteHello.java (1)
La registrazione:SetupRemoteHello.java (2)
ActivationDesc desc = new ActivationDesc
(agi, "HelloImpl", location, data);
– dichiarato in
Hello.java
20
21
MarshalledObject data = null;
• Implementazione del
metodo remoto
19
Il diagramma di ActRemoteHello
String location = "file:" + home;
/**
* Metodo remoto : restituisce una stringa
*/
public String dimmiQualcosa( String daChi )
throws RemoteException {
System.out.println( "Saluto " + daChi );
return "Ciao!";
}
24
4
"Programmazione Distribuita" - Prof.
Scarano
Laurea in Informatica
• Client identico alla
versione non activatable
• Parametri:
– args[0]: hostname
– args[1]: nome del client
Vi.ttorio Scarano
import java.rmi.*;
public class HelloClient {
public static void main( String args[] ) {
String host = "localhost";
String nome = "Pippo";
if ( args.length > 0 ) host = args[0];
if ( args.length > 1 ) nome = args[1];
try {
Hello obj = (Hello)
Naming.lookup ( "rmi://" + host +
"/RemoteHello" );
System.out.println( "Ricevuto:"
+ obj.dimmiQualcosa( nome ) );
} catch ( Exception e ) {
e.printStackTrace();
}
}
}
Esecuzione: eseguo rmid (1)
Programmazione Distribuita.
Programmazione Distribuita.
Vi.ttorio Scarano
Il client
client::HelloClient.java
25
26
Programmazione Distribuita.
Programmazione Distribuita.
Vi.ttorio Scarano
Esecuzione: lancio di setup (3)
Vi.ttorio Scarano
Esecuzione: eseguo rmiregistry (2)
27
28
Programmazione Distribuita.
Programmazione Distribuita.
Vi.ttorio Scarano
Esecuzione: cosa avviene sul server (5)
Vi.ttorio Scarano
Esecuzione: lancio del client (4)
29
A.A. 2002-2003 Università di Salerno
30
5
"Programmazione Distribuita" - Prof.
Scarano
Laurea in Informatica
Programmazione Distribuita.
Programmazione Distribuita.
Vi.ttorio Scarano
Esecuzione: cosa avviene sul server (7)
Vi.ttorio Scarano
Esecuzione: altra esecuzione client (6)
31
32
La situazione sulla macchina (2)
• Alla esecuzione del
client…
• .. fa seguito la
attivazione di una JVM
da parte di RMI per
l’oggetto HelloImpl
Programmazione Distribuita.
Programmazione Distribuita.
Vi.ttorio Scarano
• Pur essendo in
esecuzione rmid, non c’è
nessuna JVM per
l’oggetto server
Vi.ttorio Scarano
La situazione sulla macchina (1)
33
34
La persistenza dei dati
Un esempio: PersActRemoteHello
• Oramai “stranoto” servizio da offrire:
Vi.ttorio Scarano
– nel caso sia necessario prevedere il recovery da crash
– oppure nel caso in cui l’oggetto remoto decida di diventare
inattivo dopo un certo periodo di tempo,
• ma alla prima invocazione remota vuole essere disponibile
• recuperando i dati in precedenza calcolati
Programmazione Distribuita.
Programmazione Distribuita.
Vi.ttorio Scarano
• Particolarmente importante:
• A questo scopo si usano i dati da fornire durante la
attivazione
– che possono essere usati dal costruttore chiamato per la
attivazione
35
A.A. 2002-2003 Università di Salerno
– unica variante: in risposta fornisce anche i dati di tutti gli
utenti che hanno invocato il metodo dimmiQualcosa()
dell’oggetto remoto
– quindi necessario:
• concatenare in una stringa tutti i nomi passati come parametri alle
invocazioni remote
• prevedere il salvataggio dei dati nel caso in cui l’oggetto cada e
venga rieseguito
• A questo scopo usiamo un file:
– dove, ad ogni invocazione, HelloImpl va a scrivere la stringa
36
che compone il suo stato
6
"Programmazione Distribuita" - Prof.
Scarano
Laurea in Informatica
La interface remote: Hello.java
Vi.ttorio Scarano
public interface Hello
extends java.rmi.Remote {
String dimmiQualcosa( String daChi )
throws java.rmi.RemoteException;
}
• Identica al caso
precedente
Programmazione Distribuita.
Programmazione Distribuita.
Vi.ttorio Scarano
Il diagramma di PersActRemoteHello
37
38
Vi.ttorio Scarano
Vi.ttorio Scarano
Programmazione Distribuita.
La implementazione: HelloImpl.java (1)
Programmazione Distribuita.
Il diagramma di PersActRemoteHello
39
• Secondo costruttore
– struttura identica al
primo
Vi.ttorio Scarano
public HelloImpl(ActivationID id,
MarshalledObject data )
throws RemoteException {
super( id, 0 );
System.out.println( "Secondo costruttore " );
try {fileDati = (File) data.get();
if ( fileDati.exists () )
this.restoreState ();
else callsFrom = "[Starting...]";
} catch (Exception e) {
System.out.println(“Lettura file");
}
}
public String dimmiQualcosa( String daChi )
throws RemoteException {
System.out.println( "Saluto " + daChi );
this.saveState( daChi );
return "(dopo "+ callsFrom+")"+"Ciao!";
} // continua…
• Metodo remoto
– usa saveState() per
aggiungere il nome
del chiamante
– restituisce la intera
stringa di chiamate
oltre a “Ciao!”
A.A. 2002-2003 Università di Salerno
• Primo costruttore
– solo per istanziare e
attivare (non usato)
– identico al secondo
• Preleva il riferimento
al file inserito in data
– se esiste il file
• allora chiama
restoreState()
• altrimenti inizializza la
variabile di istanza
callsFrom
40
La implementazione: HelloImpl.java (3)
Programmazione Distribuita.
Programmazione Distribuita.
Vi.ttorio Scarano
La implementazione: HelloImpl.java (2)
import java.rmi.*;
import java.rmi.activation.*;
import java.io.*;
public class HelloImpl extends Activatable
implements Hello {
public HelloImpl( String codebase,
MarshalledObject data )
throws RemoteException, ActivationException {
super( codebase , data, false, 0 );
System.out.println( "Primo costruttore " );
try {fileDati = (File) data.get();
if ( fileDati.exists () )
this.restoreState ();
else
callsFrom = "Starting ...";
} catch (Exception e) {
System.out.println(“Lettura file");
}
} // continua…
private void restoreState() throws
IOException , ClassNotFoundException {
File f = fileDati ;
FileInputStream fis = new FileInputStream( f );
ObjectInputStream ois = new
ObjectInputStream (fis);
callsFrom = (String) ois.readObject();
ois.close ();
}
// continua
• Usa la variabile di
istanza fileDati
– apre uno stream input
da file e crea
– un object stream
– ne legge una stringa e
la inserisce nella
variabile di istanza
callsFrom
– e chiude lo stream
41
42
7
"Programmazione Distribuita" - Prof.
Scarano
Laurea in Informatica
• Usa la variabile di
istanza fileDati
– apre in output uno
stream dal file stream
– aggiorna lo stato
callsFrom ..
– … e lo scrive su file
• Variabili istanza
File fileDati ;
String callsFrom ;
}
– file per lo stato
persistente
– stato delle chiamate
Vi.ttorio Scarano
private void saveState( String currentCall ) {
try {File f = fileDati;
FileOutputStream fos = new
FileOutputStream( f );
ObjectOutputStream oos = new
ObjectOutputStream( fos );
callsFrom = callsFrom + " -" + currentCall;
oos.writeObject( callsFrom );
oos.close ();
} catch ( Exception e ) {
System.out.println( "Errore in scrittura" );
}
}
Il diagramma di PersActRemoteHello
Programmazione Distribuita.
Programmazione Distribuita.
Vi.ttorio Scarano
La implementazione: HelloImpl.java (4)
43
44
• Set SM
• Proprietà delle JVM
lanciate da rmid
– solo per test: policyall
• Creazione del gruppo
– descrittore
– group ID dalla
registrazione
Hello hi = (Hello)Activatable.register(desc);
System.out.println("Ho lo stub per HelloImpl");
Naming.rebind ("RemoteHello", hi);
System.out.println(".. e lo esporto sul registry");
} catch ( Exception e ) {
e.printStackTrace();
}
System.out.println("Salute a tutti!");
System.exit(0);
}
}
45
• URL per la posizione
dello stub
• Dati da passare alla
classe (File)
• Creazione del descrittore
di attivazione
• Registrazione
sull’activator del
descrittore di attivazione
– restituisce lo stub
– … di cui va fatto il bind
su rmiregistry
46
Programmazione Distribuita.
Programmazione Distribuita.
Vi.ttorio Scarano
Il client
client::HelloClient.java
Vi.ttorio Scarano
Il diagramma di PersActRemoteHello
47
A.A. 2002-2003 Università di Salerno
String location = "file:" + home;
MarshalledObject data = new
MarshalledObject (new File(
"/ProgettiJava/PersActRemoteHello/dati.dat"));
ActivationDesc desc = new ActivationDesc
(agi, "HelloImpl", location, data);
Vi.ttorio Scarano
import java.rmi.*;
import java.rmi.activation.*;
import java.util.Properties;
public class SetupRemoteHello {
public static void main( String args[] ) {
System.setSecurityManager( new
RMISecurityManager() );
String home = "/ProgettiJava/PersActRemoteHello ";
try {
Properties props = new Properties ();
props.put("java.security.policy", home+"/policyall");
ActivationGroupDesc.CommandEnvironment
ace = null ;
ActivationGroupDesc helloGroup = new
ActivationGroupDesc (props, ace);
ActivationGroupID agi =
ActivationGroup.getSystem().registerGroup(
helloGroup);
// continua…
La registrazione:SetupRemoteHello.java (2)
Programmazione Distribuita.
Programmazione Distribuita.
Vi.ttorio Scarano
La registrazione:SetupRemoteHello.java (1)
import java.rmi.*;
public class HelloClient {
public static void main( String args[] ) {
String host = "localhost";
String nome = "Pippo";
if ( args.length > 0 ) host = args[0];
if ( args.length > 1 ) nome = args[1];
try {
Hello obj = (Hello)
Naming.lookup ( "rmi://" + host +
"/RemoteHello" );
System.out.println( "Ricevuto:"
+ obj.dimmiQualcosa( nome ) );
} catch ( Exception e ) {
e.printStackTrace();
}
}
}
• Client identico alla
versione activatable non
persistente
• Parametri:
– args[0]: hostname
– args[1]: nome del client
48
8
"Programmazione Distribuita" - Prof.
Scarano
Laurea in Informatica
Programmazione Distribuita.
Programmazione Distribuita.
Vi.ttorio Scarano
Esecuzione: eseguo rmiregistry (2)
Vi.ttorio Scarano
Esecuzione: eseguo rmid (1)
49
50
Programmazione Distribuita.
Programmazione Distribuita.
Vi.ttorio Scarano
Cosa accade sul server (4)
Vi.ttorio Scarano
Setup ed esecuzione vari client (3)
51
52
Simuliamo un “crash”…
(come se ce ne fosse bisogno)
Alla successiva chiamata…
Vi.ttorio Scarano
Programmazione Distribuita.
Programmazione Distribuita.
Vi.ttorio Scarano
• Uccidiamo la JVM di HelloImpl…Oops!
53
A.A. 2002-2003 Università di Salerno
54
9
"Programmazione Distribuita" - Prof.
Scarano
Laurea in Informatica
Programmazione Distribuita.
Vi.ttorio Scarano
E sul server è stata istanziata un’altra JVM
55
A.A. 2002-2003 Università di Salerno
10