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

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:


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:

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