Esercizio 6: Server attivabili
In questa esercitazione lavoreremo con server attivabili. Il server
attivabile
RemActDateTimeServer viene inizializzato con oggetto
di tipo AcTrDate,
il quale tiene traccia di tre informazioni riguardanti la
vita del server attivabile:
(1) Il numero di attivazioni,
(2) Il numero delle transizioni, ovvero delle invocazioni presso il
server attivabile,
(3) l'ora presso il server remoto.
Questo oggetto viene memorizzato, e continuamente aggiornato,
all'interno
dell'Activation Descriptor associato al server attivabile.
****************************************************
1) Create un package datetimenella
directory javarmi in cui
mettere i seguenti codici:
1.a) L'interfaccia remota RemActDateTime.java che dichiara un
metodo remoto che
ritorna oggetti di tipo AcTrDate.
package datetime;
import java.rmi.*;
import java.rmi.activation.*;
import java.io.*;
public interface RemActDateTime extends Remote {
public AcTrDate remAcTrDate()
throws
ActivationException, IOException, ClassNotFoundException;
}
Notate che il metodo remoto ritorna un oggetto di tipo AcTrDate.
1.b) AcTrDate.java: Un oggetto di tipo AcTrDate e' un
oggetto di cui si possono invocare tre metodi
- getActNumber() , per fornire il numero di attivazione,
- getTransNumber() , per fornire il numero della transizione,
- getTransDateTime(), per fornire l'ora presso la macchina remota.
Questo oggetto serve per memorizzare lo stato di attivazione di un
server. Memorizzando il numero di
attivazione (ovvero quante volte e' stato attivato), il numero delle
invocazione e l'ora presso
il server remoto.
package datetime;
import java.io.*;
import java.util.Date;
public class AcTrDate implements Serializable {
int activationNumber = 0;
int transactionNumber = 0;
Date transactionDateTime;
public AcTrDate(int an, int tn, Date td){
activationNumber = an ;
transactionNumber = tn ;
transactionDateTime = td ;
}
public int getActNumber()
{return activationNumber;}
public int getTransNumber() {return
transactionNumber;}
public Date getTransDateTime() {return
transactionDateTime;}
}
1.c) L'implementazione dell'oggetto remoto RemActDateTimeServer.java
e' riportata sotto.
Come noterete, dovete dedicare particolare cura sia al costruttore che
al metodo remoto.
Notate che vie e' anche un metodo unreferenced, visto che il server
implementa l'interfaccia
Unreferenced.
package datetime;
import java.io.*;
import java.rmi.*;
import java.rmi.activation.*;
import java.rmi.server.*;
import java.util.Date;
public class RemActDateTimeServer extends Activatable
implements RemActDateTime, Unreferenced {
public RemActDateTimeServer(ActivationID
id,MarshalledObject atDate)
throws ActivationException, IOException,
ClassNotFoundException {
super(id,35000);
System.out.println("");
System.out.println(" Sono dentro il
costruttore del server.");
System.out.println(" E' stato invocato con
successo il costruttore della superclasse Activatable, ");
System.out.println(" passando come parametro
l'ActivationID "+id+" del server che verra esportato alla porta 35000
");
ActivationSystem actS =
ActivationGroup.getSystem();
System.out.println(" La referenza al sistema
di attivazione (rmid) e': "+actS);
ActivationDesc actD =
actS.getActivationDesc(id);
System.out.println("Ho ricavato l'
ActivationDescriptor "+actD+", associato al server attivabile grazie
all'ActivationID= "+id);
// Adesso creiamo un valore di default con
cui inizializzare il server.
int an = 1; int tn = 0;
if (atDate != null ) {
AcTrDate fatDate =
(AcTrDate)(atDate.get());
an =
fatDate.getActNumber()+1;
tn =
fatDate.getTransNumber();
}
AcTrDate natDate = new AcTrDate(an,tn,new
Date());
System.out.println(" Ho creato ed
inizializzato un oggetto " + natDate + " che terra' traccia della vita
del server ");
//Creiamo un nuovo ActivationDesc per il
nostro server attivabile che contenga anche
//Un valore di default.
ActivationDesc nad = new
ActivationDesc(actD.getGroupID(),actD.getClassName(),actD.getLocation(),
new MarshalledObject(natDate));
System.out.println(" Ho creato un nuovo
ActivationDescriptor "+nad+" contenente il nuovo oggetto AcTrDate:
"+natDate);
actD = actS.setActivationDesc(id,nad);
System.out.println(" Ho aggiornato
l'ActivationDesc "+ actD+" del server attivabile, con l'informazione
contenuta nell'ActivationDesc appena creato.");
System.out.println(" Questa e' l'ultima
istruzione del costruttore del server attivabile");
}
//
// IMPLEMENTAZIONE DEL METODO REMOTO DEL
SERVER
//
public AcTrDate remAcTrDate()
throws ActivationException,
IOException, ClassNotFoundException {
System.out.println(" Sono dentro
l'implementazione del metodo remoto remAcTrDate() del server
attivabile");
ActivationSystem actS =
ActivationGroup.getSystem();
System.out.println(" Ho ottenuto la seguente
referenza al sistema di attivazione: "+actS);
ActivationID id = getID();
//geID() e' un metodo di Activatable che
torna l'ID associato al server
System.out.println(" Ho ottenuto il
seguente ActivationID del server: "+id);
ActivationDesc actD =
actS.getActivationDesc(id);
System.out.println(" Grazie a tale
ActivationID ho ricavato l' ActivationDescriptor del server: "+actD);
// Ricavo l'oggetto di tipo AcTrDate con cui
il server e' correntemente settato.
Object object =
((MarshalledObject)actD.getData()).get();
AcTrDate fatDate = (AcTrDate)object;
System.out.println("Dall'Activation
Descriptor del server estraggo l'oggetto di tipo AcTrDate con cui il
server e' correntemente settato: "+fatDate);
int an = fatDate.getActNumber();
int tn = fatDate.getTransNumber()+1;
System.out.println("Creo un nuovo
oggetto AcTrDate con il medesimo Activation Number, incremento il
Transition Number, e prendo la data corrente");
AcTrDate natDate = new
AcTrDate(an,tn,new Date());
System.out.println(" Ho creato il nuovo
oggetto AcTrDate: "+natDate);
ActivationDesc nad = new
ActivationDesc(actD.getGroupID(),actD.getClassName(),
actD.getLocation(), new MarshalledObject(natDate));
System.out.println(" Ho creato un nuovo
ActivationDescriptor "+nad+" contenente il nuovo oggetto
AcTrDate");
actD = actS.setActivationDesc(id,nad);
System.out.println(" Ho aggiornato
l'ActivationDesc "+ actD+" del server, con l'informazione contenuta
nell'ActivationDesc appena creato.");
System.out.println(" Questa e' l'ultima
istruzione del metodo remoto del server.");
return natDate;
}
//
// IMPLEMENTAZIONE DEL METODO UNREFERENCED
//
public void unreferenced() {
try {
System.out.println(" Sono dentro il metodo unreferenced del server
remoto: " + this);
Naming.unbind("//:1098/" + RemActDateTime.class.getName);
boolean ok =
inactive(getID());
//
System.out.println(" Ho invocato il metodo inactive per
disattivare il server attivabile");
System.out.println("
Tale metodo si occupa anche di de-esportare il server");
System.out.println(" Il server "+this+" e' inattivo? "+ok);
//
Get myself collected
System.out.println(" Sto invocando il garbage collector dentro la JVM
del server attivabile");
System.gc();
System.out.println(" Sto uscendo dal metodo unreferenced.");
}
catch (Exception e) {
System.out.println("unreferenced: "+e);
System.out.close();
}
}
}
1.d) Il programma Setup.java si occupa di fare il set-up del
server remoto, ovvero:
- Si crea un gruppo di attivazione che viene registrato col
sistema di attivazione.
- Si crea un'istanza del server attivabile che viene
registrata col gruppo creato.
- Si registra il server attivabile su un registro RMI (in
questo caso quello alla porta 1098 usato da rmid)
- Infine, viene invocato un metodo di test che fa le seguenti cose:
- Una lookup sul registro 1098 per ottenere una referenza remota al
server.
- Invoca il metodo remoto del server attraverso lo stub ricavato
con la lookup.
- Visualizza il risultato dell'invocazione remota.
package datetime;
import java.io.*;
import java.net.*;
import java.rmi.*;
import java.rmi.activation.*;
import java.rmi.registry.*;
import java.rmi.server.*;
import java.util.Properties;
public final class Setup {
private static void test() throws IOException,
NotBoundException, MalformedURLException,
ActivationException, ClassNotFoundException {
System.out.println("Sono
dentro il metodo test() di Setup");
System.out.println("Faccio una lookup
sul registro RMI alla porta 1098 per ricavare lo stub al server
attivabile "+RemActDateTime.class.getName());
RemActDateTime atDateServ =
(RemActDateTime)Naming.lookup("//localhost:1098/"+
RemActDateTime.class.getName());
System.out.println("La lookup ha avuto
successo ed ho ottenuto lo stub: "+atDateServ);
System.out.println("Si noti che poiche' lo
stub non e' stato ancora utilizzato la sua RemoteRef e' a null.");
System.out.println("Uso lo stub per
invocare il metodo remoto remAcTrDate() del server attivabile");
System.out.println("Poiche'
e' la prima invocazione, cio' causera' il lancio della JVM del gruppo di
attivazione relativo e successivamente il lancio del server.");
System.out.println("Tale operazione
prendera' qualche secondo");
AcTrDate atDate =
atDateServ.remAcTrDate();
System.out.println("Visualizzo il
risultato dell'invocazione: activation indica il numero di volte che e'
stato attivato il server; transaction e' il numero
dell'invocazioni remote al server, infine viene fornita la data
remota.");
System.out.println("activation n.
"+atDate.getActNumber()+", "+"transaction n.
"+atDate.getTransNumber()+", "+"at remote date&time
"+atDate.getTransDateTime());
System.out.println("Visualizzo
nuovamente lo stub al server dopo l'invocazione: "+atDateServ);
System.out.println("Notate che adesso,
dopo la prima invocazione, la RemoteRef non e' piu' a null!!");
}
public static void main(String args[]) {
System.out.println("");
System.out.println("Inizia la procedura
main di Setup");
// INIZIALIZZAZIONI
String policyGroup =
System.getProperty("datetime.policy");
String implCodebase =
System.getProperty("datetime.impl.codebase");
String classeserver =
System.getProperty("datetime.classeserver");
// LANCIO IL SECURITY MANAGER
System.setSecurityManager(new
RMISecurityManager());
try {
Properties prop = new Properties();
prop.put("java.security.policy",policyGroup);
prop.put("datetime.impl.codebase", implCodebase);
prop.put("java.class.path", "no_classpath");
// FASE 1: CREAZIONE
DEL GRUPPO DI ATTIVAZIONE
ActivationGroupDesc
groupDesc = new ActivationGroupDesc(prop,null);
// FASE 2:
REGISTRAZIONE DEL GRUPPO DI ATTIVAZIONE
ActivationGroupID groupID =
ActivationGroup.getSystem().registerGroup(groupDesc);
System.out.println("Il gruppo e' stato creato, registrato col
sistema d'attivazione, ed ha identificativo = "+groupID);
// FASE 3: CREAZIONE
DELL'ACTIVATION DESCRIPTOR ASSOCIATO AL SERVER
ActivationDesc
actDesc = new ActivationDesc(groupID, classeserver, implCodebase, null);
// FASE 4: REGISTRAZIONE DEL
SERVER ATTIVABILE COL SISTEMA D'ATTIVAZIONE
RemActDateTime stub_server =
(RemActDateTime)Activatable.register(actDesc);
System.out.println("E' stato creato l'activation descriptor del
server che e' stato registrato col demone d'attivazione");
System.out.println("Il server attivabile che adesso puo' essere acceduto
attraverso lo stub: "+stub_server);
System.out.println("Notate come la RemoteRef dello stub sia a null");
// FASE 5: BINDING DEL
SERVER ATTIVABILE SUL REGISTRO RMI
System.out.println("Faccio il binding dello stub del server attivabile
nel registro RMI alla porta 1098 dove gia' si trova registrato il
sistema di attivazione ");
Naming.rebind("//:1098/"+ RemActDateTime.class.getName(), stub_server);
System.out.println("Adesso invoco il metodo test della classe Setup");
test();
System.out.println("E' terminato il metodo test() della classe
Setup");
}
catch (Throwable t){
t.printStackTrace();
}
}
}
1.e) Mettete in javarmi/datetime un file di setup.policy, il file di policy del
codice di setup,
(inizialmente uguale al file di
policy che fornisce tutti i permessi)
1.f) Mettete sempre in javarmi/datetime/
un file rmid.policy, il file di
policy di rmid, anche questo
inizialmente fornisce tutti i permessi.
1.g) Infine, sempre in javarmi/datetime/
create un file di policy group.policy,
il file di policy del
gruppo di attivazione. Anche questo, inizialmente che dia tutti i
permessi.
2) Compiliamo i sorgenti in datetime con javac *.java
3) facciamo la compilazione rmic da javarmi
digitando:
rmic -d home/....../public_html/common/
datetime.RemActDateTimeServer
4) Nota che l'implementazione del server, cioe' la classe
RemActDateTimeServer.class, deve essere
caricata dinamicamente dal sistema di attivazione al momento
dell'attivazione del server attivabile.
Per tale ragione spostiamo la sua classe, insieme alle classi
RemActDateTime.class e AcTrDate.class,
nel codebase /home/.../public_html/common/datetime/. Nella
directory javarmi/activation/datetime/
restera' quindi una sola classe, la Setup.class.
L'unica che deve essere usata una volta sola quando si
lancia il Setup. Tale classe non verra' caricata dinamicamente.
5) Adesso in una finestra del
server, nella vostra home directory, lanciate il sistema rmid,
sostituendo codebase e indirizzo di policy opportuni. Create un file
rmid.policy
IMPORTANTE: lanciamo rmid in una finestra differente del server.
rmid -log /home/..../javarmi/datetime/log-rmid/
-J-Djava.rmi.server.codebase=file:///home/..../common/
-J-Djava.security.policy=/home/..../javarmi/datetime/rmid.policy &
L'attivazione di rmid vi creera' una directory su disco, li' dove avete
indicato col parametro -log
Tale directory di log conterra' i file di log e conterra' le
informazioni per riattivare i server
attivabili registrati col sistema di attivazione. Poiche tale
informazione e' persistente
(e' scritta su disco) i server attivabili sono persistenti e possono
essere riattivati anche dopo
un reboot del server, rilanciando il sistema di attivazione.
6) Lanciamo il programma di setup dalla directory activation in un altra finestra del server:
java -classpath :/home.../public_html/common/
-Djava.rmi.server.codebase=file:///home/...../common/
-Ddatetime.impl.codebase =
file:///home/..../common/
-Djava.security.policy=/home/
.../javarmi/datetime/setup.policy
-Ddatetime.classeserver=datetime.RemActDateTimeServer
-Ddatetime.policy=/home/..../javarmi/datetime/group.policy
datetime.Setup
- Nella finestra in cui e' stato
lanciato il codice di Setup vi apparira' una videata di questo tipo:
Inizia
la procedura main di Setup
Il codebase utilizzato durante
l'attivazione e': file:///home/massimo/public_html/common/activation/
Creo un gruppo di attivazione e lo
registro col sistema di attivazione
Il gruppo e' stato registrato, ed ha
identificativo groupID= java.rmi.activation.ActivationGroupID@b6524b41
Iniziamo adesso la fase di
registrazione del server attivabile utilizzando il groupID
Ho registrato il server attivabile
che adesso puo' essere acceduto attraverso lo stub:
datetime.RemActDateTimeServer_Stub[RemoteStub [ref: null]]
Notate come la RemoteRef dello stub
sia a null
Faccio il binding dello stub
datetime.RemActDateTimeServer_Stub[RemoteStub [ref: null]], del server
attivabile datetime.RemActDateTime, nel registro RMI alla porta 1098
dove gia' si trova registrato il sistema di attivazione
sun.rmi.server.Activation$ActivationSystemImpl_Stub[RemoteStub [ref:
[endpoint:[127.0.0.1:1098](remote),objID:[0:0:0, 4]]]]
Adesso invoco il metodo test della
classe Setup
Sono dentro il metodo test() di Setup
Faccio una lookup sul registro RMI
alla porta 1098 per ricavare lo stub al server attivabile
datetime.RemActDateTime
La lookup ha avuto successo ed ho
ottenuto lo stub datetime.RemActDateTimeServer_Stub[RemoteStub [ref:
null]]
Si noti che poiche' lo stub non e'
stato ancora utilizzato la sua RemoteRef e' a null.
Uso lo stub per invocare il metodo
remoto remAcTrDate() del server attivabile
Poiche' e' la prima invocazione, cio'
causera' il lancio della JVM del gruppo di attivazione relativo e
successivamente il lancio del server.
Tale operazione prendera' qualche
secondo
Visualizzo il risultato
dell'invocazione: activation indica il numero di volte che e' stato
attivato il server; transaction e' il numero dell'invocazioni remote al
server, infine viene fornita la data remota.
activation n. 1, transaction n. 1, at
remote date&time Mon May 24 11:24:51 CEST 2004
Visualizzo nuovamente lo stub al
server dopo l'invocazione: datetime.RemActDateTimeServer_Stub[RemoteStub
[ref: sun.rmi.server.UnicastRef2@bfc93a]]
Notate che adesso, dopo la prima
invocazione, la RemoteRef non e' piu' a null
E' terminato il metodo test() della
classe Setup
Studiate attentamente queste righe di codice per capire esattamente
cosa avviene e dove avviene.
7) Notate che nella finestra in cui e' stato lanciato il sistema di
attivazione RMID, nel momento stesso
in cui si invoca il metodo del server e quindi (poiche' e' inizialmente
inattivo) lo si attiva, appare la
schermata riportata sotto. Tale schermata, mostra che, prima di
eseguire il costruttore del server, viene
lanciato un gruppo d'attivazione. Dopodiche', poiche' il server era
inattivo, vengono prima eseguite le
istruzioni all'interno del costruttore e solo dopo le istruzioni del
metodo remoto invocato. Si noti che
il gruppo di attivazione ed il suo server vanno in esecuzione su una
JVM differente da rmid.
Mon May 24 11:24:50 CEST
2004:ExecGroup-0:out:
Mon May 24 11:24:51 CEST
2004:ExecGroup-0:out: Sono dentro il costruttore del server.
Mon May 24 11:24:51 CEST
2004:ExecGroup-0:out: E' stato invocato con successo il costruttore
della superclasse Activatable,
Mon May 24 11:24:51 CEST
2004:ExecGroup-0:out: passando come parametro l'ActivationID
java.rmi.activation.ActivationID@b6524b43 del server.
Mon May 24 11:24:51 CEST
2004:ExecGroup-0:out: La referenza al sistema di attivazione e':
sun.rmi.server.Activation$ActivationSystemImpl_Stub[RemoteStub [ref:
[endpoint:[127.0.0.1:1098](remote),objID:[0:0:0, 4]]]]
Mon May 24 11:24:51 CEST
2004:ExecGroup-0:out: Ho ricavato l' ActivationDescriptor
java.rmi.activation.ActivationDesc@1af5200, associato al server
attivabile grazie all'ActivationID=
java.rmi.activation.ActivationID@b6524b43
Mon May 24 11:24:51 CEST
2004:ExecGroup-0:out: Ho creato un oggetto datetime.AcTrDate@7d5d2a di
tipo AcTrDate con cui inizializzare il server.
Mon May 24 11:24:51 CEST
2004:ExecGroup-0:out: Ho creato un nuovo ActivationDescriptor
java.rmi.activation.ActivationDesc@e6db4b3a contenente il nuovo oggetto
AcTrDate: datetime.AcTrDate@7d5d2a
Mon May 24 11:24:51 CEST
2004:ExecGroup-0:out: Ho aggiornato l'ActivationDesc
java.rmi.activation.ActivationDesc@1af5200 del server, con
l'informazione contenuta nell'ActivationDesc appena creato.
Mon May 24 11:24:51 CEST
2004:ExecGroup-0:out: Questa e' l'ultima istruzione del costruttore del
server attivabile
Mon May 24 11:24:51 CEST
2004:ExecGroup-0:out: Sono dentro l'implementazione del metodo remoto
remAcTrDate() del server attivabile
Mon May 24 11:24:51 CEST
2004:ExecGroup-0:out: Ho ottenuto la seguente referenza al sistema di
attivazione:
sun.rmi.server.Activation$ActivationSystemImpl_Stub[RemoteStub [ref:
[endpoint:[127.0.0.1:1098](remote),objID:[0:0:0, 4]]]]
Mon May 24 11:24:51 CEST
2004:ExecGroup-0:out: Ho ottenuto il seguente ActivationID del server:
java.rmi.activation.ActivationID@b6524b43
Mon May 24 11:24:51 CEST
2004:ExecGroup-0:out: Grazie a tale ActivationID ho ricavato l'
ActivationDescriptor del server:
java.rmi.activation.ActivationDesc@e6db4b3a
Mon May 24 11:24:51 CEST
2004:ExecGroup-0:out:Dall'Activation Descriptor del server estraggo
l'oggetto di tipo AcTrDate con cui il server e' correntemente settato:
datetime.AcTrDate@a352a5
Mon May 24 11:24:51 CEST
2004:ExecGroup-0:out:Creo un nuovo oggetto AcTrDate con il medesimo
Activation Number, incremento il Transition Number, e prendo la
data corrente
Mon May 24 11:24:51 CEST
2004:ExecGroup-0:out: Ho creato il nuovo oggetto AcTrDate:
datetime.AcTrDate@86fe26
Mon May 24 11:24:51 CEST
2004:ExecGroup-0:out: Ho creato un nuovo ActivationDescriptor
java.rmi.activation.ActivationDesc@b0586fb2 contenente il nuovo
oggetto AcTrDate
Mon May 24 11:24:51 CEST
2004:ExecGroup-0:out: Ho aggiornato l'ActivationDesc
java.rmi.activation.ActivationDesc@e6db4b3a del server, con
l'informazione contenuta nell'ActivationDesc appena creato.
Mon May 24 11:24:51 CEST
2004:ExecGroup-0:out: Questa e' l'ultima istruzione del metodo remoto
del server.
Studiate questi passi uno alla volta e comprendete esattamente cosa
succede e perche'.
7) Dopodiche' fate il seguente esperimento. Dalla macchina client
invocate la ListRegistry, vista nella lezioni
precedenti, con parametro //delta...:1098, dove delta....
e' la macchina in cui e' stato creato il server attivabile.
Otterrete una videata di questo genere:
Contents of registry at rmi://profs.sci.univr.it:1098 (2 entries)
1.
name=rmi://profs.sci.univr.it:1098/java.rmi.activation.ActivationSystem
remote=sun.rmi.server.Activation$ActivationSystemImpl_Stub[RemoteStub
[ref: [endpoint:[157.27.252.10:1098](remote),objID:[0:0:0, 4]]]]
2.
name=rmi://profs.sci.univr.it:1098/datetime.RemActDateTime
remote=datetime.RemActDateTimeServer_Stub[RemoteStub [ref: null]]
Cioe' il registro contiene due elementi. Il primo e' il sistema di
attivazione ed il secondo e' il server attivabile
datetime.RemActDateTime con referenza remota:
datetime.RemActDateTimeServer_Stub[RemoteStub [ref: null]].
8) Osservate che se spostate le classi dalla directory comune avrete
problemi in fase di attivazione
del server poiche' il sistema di attivazione non riesce a trovare le
classi per attivare il server.
Le classi necessarie per lanciare il server non sono solo gli stub ma
anche le classi dell'implementazione,
dell'interfaccia, e quelle su cui si basa l'interfaccia.
9) Passiamo a vedere il codice Client. Noi siamo interessati a
caricamento dinamico del codice del client
dalla macchina server. Quindi mettiamo il codice del client sulla
macchina del server. Piu precisamente,
sempre nella directory javarmi/datetime
del server, mettiamo due sorgenti java:
a) RemActDateTimeClient.java: che consiste nel codice
client che si appoggia su una classe factory data di seguito.
package datetime;
import java.io.*;
import java.rmi.*;
public class RemActDateTimeClient implements Runnable {
public void run() {
try {
System.out.println("Sto eseguendo
il codice del Client, caricato dinamicamente dal codebase del server");
System.out.println("Invoco il
metodo getServ di RemActDateTimeFactory per ottenere la referenza remota
al server attivabile");
RemActDateTime atDateServ =
RemActDateTimeFactory.getServ();
System.out.println("La referenza
remota ottenuta e': "+atDateServ);
System.out.println("Adesso invoco
il metodo remoto del server attivabile");
System.out.println("Cio'
causera' l'attivazione del server, se al momento e' inattivo, e
l'eventuale attivazione del gruppo di attivazione.");
AcTrDate atDate =
atDateServ.remAcTrDate();
System.out.println("Ristampo
nuovamente la referenza remota del server. Notate che la RemotRef adesso
e' definita: "+atDateServ);
System.out.println("Visualizzo il
risultato dell'invocazione remota. Ovvero l'informazione racchiusa
nell'oggetto AcTrDate.");
System.out.println("Activation
indica quante volte e' stato attivato il server, transaction conta le
invocazione, ed infine diamo l'ora remota.");
System.out.println("activation n.
"+atDate.getActNumber()+", "+
"transaction n.
"+atDate.getTransNumber() + ", " +
"at remote date&time
"+atDate.getTransDateTime()
);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
b) RemActDateTimeFactory.java (sostituite i miei dati con i
vostri).
Tale classe si occupa di recuperare la referenza remota da un file
locale, se esiste,
oppure facendo una lookup sul registro RMI del server per poi
memorizzare tale
referenza nel file locale per future invocazioni remote.
package datetime;
import java.io.*;
import java.rmi.*;
import java.net.*;
public class RemActDateTimeFactory {
static final String reg = "//delta010:1098/";
//host e porta porta dove si trova il
registro RMI
static final String saveProt="file://";
static final String
saveRef=System.getProperty("user.dir")+"/.RemAcTrDateTimeRef";
//questo e' il file locale al client in cui
memorizzo la referenza remota.
//user.dir vuol dire la directory corrente. Percio'
nella directory corrente
// del cliente viene memorizzato la referenza nel
file .RemAcTrDateTimeRef.
static RemActDateTime persRef = null;
public static RemActDateTime getServ() throws
IOException, NotBoundException,
ClassNotFoundException,
java.net.MalformedURLException {
System.out.println("Sono
dentro il metodo getServ() di RemActDateTimeServer");
if (persRef == null)
try {
InputStream in = new
URL(saveProt+saveRef).openStream();
System.out.println("Il file
.RemAcTrDateTimeRef dove memorizziamo la referenza all'oggetto
attivabile e' stato trovato.");
System.out.println("Facciamo
allora l'unmarshalling per ottenere la referenza dal file.");
ObjectInputStream oin = new
ObjectInputStream(in);
Object object =
((MarshalledObject)oin.readObject()).get();
persRef = (RemActDateTime)object;
}
catch (FileNotFoundException e) {
System.out.println("Il file
.RemAcTrDateTimeRef dove memorizziamo la referenza all'oggetto
attivabile NON e' stato trovato.");
System.out.println("Il file
.RemAcTrDateTimeRef dove memorizziamo la referenza all'oggetto
attivabile sara' creato in: "+saveRef);
System.out.println("Facciamo
allora una lookup sulla macchina remota per ottenere la referenza remota
all'oggetto");
persRef =
(RemActDateTime)Naming.lookup(reg+RemActDateTime.class.getName());
OutputStream out = new
FileOutputStream(saveRef);
ObjectOutputStream oout = new
ObjectOutputStream(out);
oout.writeObject(new
MarshalledObject(persRef));
oout.close();
System.out.println("Dopodiche' ci
preoccupiamo di salvare la referenza remota al server attivabile, nel
file .RemAcTrDateTimeRef, della directory corrente per successive
invocazioni.");
}
return persRef;
}
}
10) Compilate presso il server, in javarmi/datetime
le classi client con le relative
interfacce remote:
javac RemActDateTime.java
AcTrDate.java RemActDateTimeClient.java
RemActDateTimeFactory.java
11) Dopodiche' spostate le classi generate in una seconda area comune
del server
~/public_html/common/datetime/ ,
accertandovi di fornire i diritti di lettura ed esecuzione. Facciamo
allora:
mv RemActDateTime.class AcTrDate.class
RemActDateTimeClient.class
RemActDateTimeFactory.class ~/public_html/common/datetime/
12) Andiamo adesso nella macchina Client. E mettiamo nella
directory ~/javarmi/datetime/
il seguente codice minimale per il caricamento dinamico delle classi
clienti: URLClientBootstrap.java
(anche qui sostituire i mie dati con quelli vostri)
package datetime;
import java.io.*;
import java.net.*;
import java.rmi.server.*;
public class URLClientBootstrap{
static final String codebase =
"........................public_html/common/"; //Codebase da cui caricare la classe Client
//qui va messa l'area condivisa da cui caricare il
client.
static final String clientClass =
"datetime.RemActDateTimeClient";
public static void main(String[] args) throws
Exception{
System.setSecurityManager(new SecurityManager());
Class cl =
RMIClassLoader.loadClass(codebase,clientClass);
Runnable client = (Runnable)cl.newInstance();
client.run();
}
}
13) Nella directory datetime del client aggiungiamo il file di policy
(visto che vi e' il caricamento di codice dinamico).
14) Compiliamo il sorgente sopra indicato.
15) Lanciamo il codice di bootstrap dalla macchina client, dalla
directory javarmi con:
java
-Djava.security.policy=/home/..../policy datetime.URLClientBootstrap
16) La prima volta che lo lanciate vi apparira' una videata del tipo:
Sto eseguendo il codice del Client,
caricato dinamicamente dal codebase del server
Invoco il metodo getServ di
RemActDateTimeFactory per ottenere la referenza remota al server
attivabile
Sono dentro il metodo getServ() di
RemActDateTimeServer
Il file .RemAcTrDateTimeRef dove
memorizziamo la referenza all'oggetto attivabile NON e' stato trovato.
Il file .RemAcTrDateTimeRef dove
memorizziamo la referenza all'oggetto attivabile sara' creato in:
/home/massimo/javarmi/activation/CLIENT/.RemAcTrDateTimeRef
Facciamo allora una lookup sulla
macchina remota per ottenere la referenza remota all'oggetto
Dopodiche' ci preoccupiamo di salvare
la referenza remota al server attivabile, nel file .RemAcTrDateTimeRef,
della directory corrente per successive invocazioni.
La referenza remota ottenuta e':
datetime.RemActDateTimeServer_Stub[RemoteStub [ref: null]]
Adesso invoco il metodo remoto del
server attivabile
Cio' causera' l'attivazione del
server, se al momento e' inattivo, e l'eventuale attivazione del gruppo
di attivazione.
Ristampo nuovamente la referenza
remota del server. Notate che la RemotRef adesso e' definita:
datetime.RemActDateTimeServer_Stub[RemoteStub [ref:
sun.rmi.server.UnicastRef2@1121f6]]
Visualizzo il risultato
dell'invocazione remota. Ovvero l'informazione racchiusa nell'oggetto
AcTrDate.
Activation indica quante volte e'
stato attivato il server, transaction conta le invocazione, ed infine
diamo l'ora remota.
activation n. 1, transaction n. 2, at
remote date&time Mon May 24 11:27:10 CEST 2004
-- Notate che il client cerca di vedere se ha gia' la referenza nel
file .RemAcTrDateTimeRef
della directory corrente (la mia non e' necessariamente uguale alla
vostra). Poiche' e' la prima volta,
non trovera' tale file e' tentera' di fare una looup sul registro alla
porta 1098 per ottenere lo stub al
server. Una volta ottenuta la referenza verra memorizzata nel file
.RemAcTrDateTimeRef per successivi
accessi.
-- L'ultima linea sta ad indicare che l'oggetto e' stato attivato una
volta (dalla Setup) ed invocato due volte (una volta dal
metodo test della Setup ed un'altra adesso). Infine viene fornita l'ora
di invocazione.
17) Nel frattempo nella finestra dove e' stato lanciato il sistema di
attivazione viene notato che l'oggetto e' stato invocato.
E poiche' l'oggetto era disattivo viene attivato insieme al suo
gruppo di attivazione ed appare la seguente videata:
Per verificare che il server e' attivo basta digitare il comando ps
dalla finestra di RMID per notare che c'e' un processo
java in esecuzione. Per l'appunto il server attivabile.
Mon May 24 11:27:10 CEST
2004:ExecGroup-0:out: Sono dentro l'implementazione del metodo remoto
remAcTrDate() del server attivabile
Mon May 24 11:27:10 CEST
2004:ExecGroup-0:out: Ho ottenuto la seguente referenza al sistema di
attivazione:
sun.rmi.server.Activation$ActivationSystemImpl_Stub[RemoteStub [ref:
[endpoint:[127.0.0.1:1098](remote),objID:[0:0:0, 4]]]]
Mon May 24 11:27:10 CEST
2004:ExecGroup-0:out: Ho ottenuto il seguente ActivationID del server:
java.rmi.activation.ActivationID@b6524b43
Mon May 24 11:27:10 CEST
2004:ExecGroup-0:out: Grazie a tale ActivationID ho ricavato l'
ActivationDescriptor del server:
java.rmi.activation.ActivationDesc@b0586fb2
Mon May 24 11:27:10 CEST
2004:ExecGroup-0:out:Dall'Activation Descriptor del server estraggo
l'oggetto di tipo AcTrDate con cui il server e' correntemente settato:
datetime.AcTrDate@34a7d8
Mon May 24 11:27:10 CEST
2004:ExecGroup-0:out:Creo un nuovo oggetto AcTrDate con il medesimo
Activation Number, incremento il Transition Number, e prendo la
data corrente
Mon May 24 11:27:10 CEST
2004:ExecGroup-0:out: Ho creato il nuovo oggetto AcTrDate:
datetime.AcTrDate@f78ef1
Mon May 24 11:27:10 CEST
2004:ExecGroup-0:out: Ho creato un nuovo ActivationDescriptor
java.rmi.activation.ActivationDesc@7dd386b4 contenente il nuovo
oggetto AcTrDate
Mon May 24 11:27:11 CEST
2004:ExecGroup-0:out: Ho aggiornato l'ActivationDesc
java.rmi.activation.ActivationDesc@b0586fb2 del server, con
l'informazione contenuta nell'ActivationDesc appena creato.
Mon May 24 11:27:11 CEST
2004:ExecGroup-0:out: Questa e' l'ultima istruzione del metodo remoto
del server.
IMPORTANTE:
Notate che poiche' il server
e' gia' attivo, stavolta non viene eseguito il suo costruttore e quindi
non
viene creato un nuovo gruppo di attivazione ma l'implemetazione del
metodo avviene all'interno del
gruppo di attivazione in cui il server e' stato attivato.
18) Se lanciamo ancora il client questi avra' una schermata leggermente
differente:
Sto
eseguendo il codice del Client, caricato dinamicamente dal codebase del
server
Invoco il metodo getServ di
RemActDateTimeFactory per ottenere la referenza remota al server
attivabile
Sono dentro il metodo getServ() di
RemActDateTimeServer
Il file .RemAcTrDateTimeRef dove
memorizziamo la referenza all'oggetto attivabile e' stato trovato.
Facciamo allora l'unmarshalling per
ottenere la referenza dal file.
La referenza remota ottenuta e':
datetime.RemActDateTimeServer_Stub[RemoteStub [ref: null]]
Adesso invoco il metodo remoto del
server attivabile
Cio' causera' l'attivazione del
server, se al momento e' inattivo, e l'eventuale attivazione del gruppo
di attivazione.
Ristampo nuovamente la referenza
remota del server. Notate che la RemotRef adesso e' definita:
datetime.RemActDateTimeServer_Stub[RemoteStub [ref:
sun.rmi.server.UnicastRef2@388993]]
Visualizzo il risultato
dell'invocazione remota. Ovvero l'informazione racchiusa nell'oggetto
AcTrDate.
Activation indica quante volte e'
stato attivato il server, transaction conta le invocazione, ed infine
diamo l'ora remota.
activation n. 1, transaction n. 3, at
remote date&time Mon May 24 11:33:36 CEST 2004
-Infatti la prima volta il client ha cercato nella vostra
directory corrente (javarmi) il file
.RemAcTrDateTimeRef per ottenere la referenza remota all'oggetto
attivabile. Tale file non esisteva
ancora e quindi e' stata fatta fatta la lookup nel registro RMI alla
porta 1098 per ottenere la referenza
che e' poi e' stata memorizzata nel file suddetto (nella directory
corrente) per le successive invocazioni.
- La seconda volta il client non ha bisogno di fare la lookup e
ricava la referenza remota all'oggetto
attivabile dal suo file locale .RemAcTrDateTimeRef dove
l'ha memorizzato la prima volta.
- Inoltre l'ultima linea evidenzia che il server e' stato attivato due
volte ed invocato 3 volte.
Infatti l'ultima volta, essendo gia' attivo lo si e' invocato
senza doverlo attivare prima.
19) Anche qui studiate attentamente il codice del client che viene
caricato dinamicamente.
20) Per verificare la persistenza della referenza remota al server
attivabile andate sul server,
sulla finestra di rmid e fate rmid -stop; vi apparira' una
scritta: activation daemon shut down.
Tale comando causa infatti lo shut-down del sistema di attivazione rmid
ed anche lo shut-down
del registro RMI alla porta 1098, come potete verificare
rilanciando ListRegistry. Infatti se
rilanciate ListRegistry sul registro alla porta 1098 ritornera'
un'eccezione perche' non trova
piu' il registro.
Se adesso provate a rilanciare il Client avrete un'eccezione perche'
lo stub non trova il sistema di attivazione con cui interagire.
22) Se pero' rilanciate il sistema di attivazione rmid, come fatto
prima, allora potete subito dopo
rilanciare il client che, invocando il metodo remoto causera'
l'attivazione del server remoto.
Come viene evidenziato nella finestra sul server dove e' stato lanciato
rmid. Notate che rilanciando
rmid rilanciate anche il registro RMI alla porta 1098 (se non
diversamente specificato)
in cui pero' stavolta vi sara' registrato il solo sistema di
attivazione (potete verificarlo con la
Listregistry). Infatti il server lo avevamo espressamente
registrato nella setup.
-Il client avra' la videata seguente in cui viene evidenziato che il
server e' stato attivato per la
seconda volta (ed invocato per la quarta volta)!
Sto eseguendo il codice del Client,
caricato dinamicamente dal codebase del server
Invoco il metodo getServ di
RemActDateTimeFactory per ottenere la referenza remota al server
attivabile
Sono dentro il metodo getServ() di
RemActDateTimeServer
Il file .RemAcTrDateTimeRef dove
memorizziamo la referenza all'oggetto attivabile e' stato trovato.
Facciamo allora l'unmarshalling per
ottenere la referenza dal file.
La referenza remota ottenuta e':
datetime.RemActDateTimeServer_Stub[RemoteStub [ref: null]]
Adesso invoco il metodo remoto del
server attivabile
Cio' causera' l'attivazione del
server, se al momento e' inattivo, e l'eventuale attivazione del gruppo
di attivazione.
Ristampo nuovamente la referenza
remota del server. Notate che la RemotRef adesso e' definita:
datetime.RemActDateTimeServer_Stub[RemoteStub [ref:
sun.rmi.server.UnicastRef2@388993]]
Visualizzo il risultato
dell'invocazione remota. Ovvero l'informazione racchiusa nell'oggetto
AcTrDate.
Activation indica quante volte e'
stato attivato il server, transaction conta le invocazione, ed infine
diamo l'ora remota.
activation n. 2, transaction n. 4, at
remote date&time Mon May 24 11:35:50 CEST 2004
Poiche' sul registro RMI alla porta 1098 non vi e' piu' la referenza
remota al server ne deriva che
il client funziona solo perche' prende la referenza remota all'oggetto
dal file locale .RemAcTrDateTimeRef
dove l'aveva memorizzata precedentemente. Se pero' cancellaste il file
.RemAcTrDateTimeRef, il client proverebbe
a fare la lookup sul registro RMI alla porta 1098 e fallirebbe perche'
non vi troverebbe piu' la referenza remota
al server remoto attivabile.
23) Se non interagite con il server attivabile per un 'po di
tempo (5-10 minuti) lui si disattivera' da solo,
a seguito dell'invocazione del metodo unreferenced da parte del sistema
RMI, e sulla finestra di RMID apparira'
qualcosa del genere:
Mon
May 24 11:50:49 CEST 2004:ExecGroup-0:out: Sono dentro il metodo
unreferenced del server remoto: datetime.RemActDateTimeServer[RemoteStub
[ref: [endpoint:[127.0.0.1:48163](local),objID:[1]]]]
Mon May 24 11:50:49 CEST
2004:ExecGroup-0:out: Ho invocato il metodo inactive per disattivare il
server attivabile
Mon May 24 11:50:49 CEST
2004:ExecGroup-0:out: Il server datetime.RemActDateTimeServer[RemoteStub
[ref: [endpoint:[127.0.0.1:48163](local),objID:[1]]]] e' inattivo? true
Mon May 24 11:50:49 CEST
2004:ExecGroup-0:out: Sto invocando il garbage collector dentro la JVM
del server attivabile
Mon May 24 11:50:49 CEST
2004:ExecGroup-0:out: Sto uscendo dal metodo unreferenced.
24) Se dopo la disattivazione automatica un'ulteriore invocazione da
parte del client causera'
Lo riattivazione del server con una videata di questo tipo sullo
schermo del client, segnalando
che il server e' stato attivato per la terza volta:
Sto eseguendo il codice del Client,
caricato dinamicamente dal codebase del server
Invoco il metodo getServ di
RemActDateTimeFactory per ottenere la referenza remota al server
attivabile
Sono dentro il metodo getServ() di
RemActDateTimeServer
Il file .RemAcTrDateTimeRef dove
memorizziamo la referenza all'oggetto attivabile e' stato trovato.
Facciamo allora l'unmarshalling per
ottenere la referenza dal file.
La referenza remota ottenuta e':
datetime.RemActDateTimeServer_Stub[RemoteStub [ref: null]]
Adesso invoco il metodo remoto del
server attivabile
Cio' causera' l'attivazione del
server, se al momento e' inattivo, e l'eventuale attivazione del gruppo
di attivazione.
Ristampo nuovamente la referenza
remota del server. Notate che la RemotRef adesso e' definita:
datetime.RemActDateTimeServer_Stub[RemoteStub [ref:
sun.rmi.server.UnicastRef2@388993]]
Visualizzo il risultato
dell'invocazione remota. Ovvero l'informazione racchiusa nell'oggetto
AcTrDate.
Activation indica quante volte e'
stato attivato il server, transaction conta le invocazione, ed infine
diamo l'ora remota.
activation n. 3, transaction n. 5, at
remote date&time Mon May 24 11:56:25 CEST 2004
25) Mentre sullo schermo del server dove e' stato lanciato rmid
apparira' una videata che evidenzia il fatto che
il server viene riattivato e cosi' anche il suo gruppo di attivazione
che era stato disattivato poice' contenente un solo
server. Se invece, volete impedire ulteriori riattivazioni del
server da parte di clients, allora
nel metodo unreferenced invece di usare il metono inactive() avreste dovuto usare il
metodo
unregister() di Activatable.
Mon May 24 11:56:24 CEST
2004:ExecGroup-1:out:
Mon May 24 11:56:24 CEST 2004:ExecGroup-1:out: Sono dentro il
costruttore del server.
Mon May 24 11:56:24 CEST 2004:ExecGroup-1:out: E' stato invocato con
successo il costruttore della superclasse Activatable,
Mon May 24 11:56:24 CEST 2004:ExecGroup-1:out: passando come parametro
l'ActivationID java.rmi.activation.ActivationID@b6524b43 del server.
Mon May 24 11:56:24 CEST 2004:ExecGroup-1:out: La referenza al sistema
di attivazione e':
sun.rmi.server.Activation$ActivationSystemImpl_Stub[RemoteStub [ref:
[endpoint:[127.0.0.1:1098](remote),objID:[0:0:0, 4]]]]
Mon May 24 11:56:24 CEST 2004:ExecGroup-1:out: Ho ricavato l'
ActivationDescriptor java.rmi.activation.ActivationDesc@fdd224f0,
associato al server attivabile grazie all'ActivationID=
java.rmi.activation.ActivationID@b6524b43
Mon May 24 11:56:24 CEST 2004:ExecGroup-1:out: Ho creato un oggetto
datetime.AcTrDate@81edf4 di tipo AcTrDate con cui inizializzare il
server.
Mon May 24 11:56:24 CEST 2004:ExecGroup-1:out: Ho creato un nuovo
ActivationDescriptor java.rmi.activation.ActivationDesc@e62ea04e
contenente il nuovo oggetto AcTrDate: datetime.AcTrDate@81edf4
Mon May 24 11:56:25 CEST 2004:ExecGroup-1:out: Ho aggiornato
l'ActivationDesc java.rmi.activation.ActivationDesc@fdd224f0 del server,
con l'informazione contenuta nell'ActivationDesc appena creato.
Mon May 24 11:56:25 CEST 2004:ExecGroup-1:out: Questa e' l'ultima
istruzione del costruttore del server attivabile
Mon May 24 11:56:25 CEST 2004:ExecGroup-1:out: Sono dentro
l'implementazione del metodo remoto remAcTrDate() del server attivabile
Mon May 24 11:56:25 CEST 2004:ExecGroup-1:out: Ho ottenuto la seguente
referenza al sistema di attivazione:
sun.rmi.server.Activation$ActivationSystemImpl_Stub[RemoteStub [ref:
[endpoint:[127.0.0.1:1098](remote),objID:[0:0:0, 4]]]]
Mon May 24 11:56:25 CEST 2004:ExecGroup-1:out: Ho ottenuto il seguente
ActivationID del server: java.rmi.activation.ActivationID@b6524b43
Mon May 24 11:56:25 CEST 2004:ExecGroup-1:out: Grazie a tale
ActivationID ho ricavato l' ActivationDescriptor del server:
java.rmi.activation.ActivationDesc@e62ea04e
Mon May 24 11:56:25 CEST 2004:ExecGroup-1:out:Dall'Activation
Descriptor del server estraggo l'oggetto di tipo AcTrDate con cui il
server e' correntemente settato: datetime.AcTrDate@97a560
Mon May 24 11:56:25 CEST 2004:ExecGroup-1:out:Creo un nuovo oggetto
AcTrDate con il medesimo Activation Number, incremento il Transition
Number, e prendo la
data corrente
Mon May 24 11:56:25 CEST 2004:ExecGroup-1:out: Ho creato il nuovo
oggetto AcTrDate: datetime.AcTrDate@ea5671
Mon May 24 11:56:25 CEST 2004:ExecGroup-1:out: Ho creato un nuovo
ActivationDescriptor java.rmi.activation.ActivationDesc@b3abb720
contenente il nuovo oggetto AcTrDate
Mon May 24 11:56:25 CEST 2004:ExecGroup-1:out: Ho aggiornato
l'ActivationDesc java.rmi.activation.ActivationDesc@e62ea04e del server,
con l'informazione contenuta nell'ActivationDesc appena creato.
Mon May 24 11:56:25 CEST 2004:ExecGroup-1:out: Questa e' l'ultima
istruzione del metodo remoto del server.
26) Fate il seguente esperimento. Arrestate rmid, e cancellate la directory dei log.
Dopodiche'
rilanciate rmid e provate a lanciare il client. Vedrete che il
client fallisce poiche' la referenza che ha
memorizzato nel file .RemAcTrDateTimeRef non e' piu' valida dato che il
database del sistema di
attivazione e' stato distrutto. Non serve neppure cancellare il file
=.RemAcTrDateTimeRef e forzare
il client a fare una lookup sul registro RMI, perche' come detto
in tale registro non vi e' piu' uno stub al
server attivabile. L'unica possibilita' e rifare il Setup in cui si
creano il gruppo di attivazione ed il
server attivabile.
27) Si noti che quando si lancia il codice di Setup avvengono le
seguenti cose:
- Viene creato un nuovo gruppo di attivazione che viene registrato
con il sistema di attivazione.
- Viene creato un nuovo server attivabile di cui si ottiene una
referenza remota.
- Si registra il server appena creato con il gruppo di attivazione
creato precedentemente.
Di conseguenza, quando il client ottiene una referenza ad un server,
interagira' sempre col
medesimo gruppo di attivazione di quel server.
Fate allora il seguente esperimento. Dopo aver rilanciato il sistema
rmid e cancellati i file
.RemAcTrDateTimeRef, contenenti referenze ormai obsolete,
lanciate in sequenza:
(i) la Setup dalla macchina server; (ii) l'applicazione client da
una certa macchina client,
(iii) nuovamente la Setup dalla macchina server, (iv) ed un'altra volta
l'applicazione Client
ma da un'altra macchina (e' sufficiente da un'altra directory che
non abbia accesso al
file .RemAcTrDateTimeRef). Vi renderete conto che la prima applicazione
client interagisce con un'istanza del server registrata con un gruppo
di attivazione, mentre la seconda
applicazione client interagisce con un'altra istanza del server
registrato con un altro gruppo di attivazione.
Tale registrazione e' avvenuta durante la seconda esecuzione di Setup.
E' facile osservare che le
due applicazioni ritornano valori differenti di activation e
transition number perche si riferiscono
a due server differenti registrati con gruppi di attivazione diversi.
Il fatto che si lavori con gruppi
diversi puo' essere anche osservato dalle videate che appaiono sulla
finestra di rmid.
28) Per ultimo rifare l'esercizio costruendo i file di policy minimi
per lo meno per quanto
riguarda:
1) Il client
2) Il file di policy rmid.policy
3) Il file di policy group.policy
Per dettagli su questi file potete andare al tutorial http://java.sun.com/j2se/1.5.0/docs/guide/rmi/activation/overview.html