Esercizio 7: Server attivabili parte II.


Questa volta avremo un server ed un client. Il server avra' degli oggetti attivabili. Il client avra' una procedura di bootstrap dalla quale carichera' dinamicamente le classi clienti  necessarrie che si occuperanno di invocare l'oggetto remoto e quindi di attivarlo. Cominciamo col descrivere il codice da mettere sulla macchina server. Ricordate di sostituire
 i miei dati con i vostri. Io ho assunto che il server giri su prof.sci.univr.it. Voi dovete usare la vostra macchina.

1) Nella directory javarmi/activation create una sottodirectory datetime in cui mettere i seguenti codici:


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;
}

b) AcTrDate.java: Un oggetto 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.

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;}
}



c) L'implementazione dell'oggetto remoto RemActDateTimeServer.java : (NEW)

package datetime;
import java.io.*;
import java.rmi.*;
import java.rmi.activation.*;
import java.rmi.server.*;
import java.util.Date;

//import javarmi.mytests.activation.datetime.AcTrDate;
//import javarmi.mytests.activation.datetime.RemActDateTime;

public class RemActDateTimeServer extends  Activatable
                                                                         implements RemActDateTime, Unreferenced
{
 public RemActDateTimeServer(ActivationID id,MarshalledObject atDate)
  throws ActivationException, IOException, ClassNotFoundException
 {
  super(id,0);
  System.out.println("Sono dentro il costruttore dell'oggetto remoto.");
  ActivationSystem as = ActivationGroup.getSystem();
  System.out.println("Ho ottenuto la seguente referenza al sistema di attivazione: "+as);
  ActivationDesc   ad = as.getActivationDesc(id);
 System.out.println("E' stato costruito l' ActivationDescriptor: "+ad);
  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());
  ActivationDesc nad = new ActivationDesc(ad.getGroupID(),ad.getClassName(),
                            ad.getLocation(), new MarshalledObject(natDate));
  as.setActivationDesc(id,nad);
  System.out.println("Ho attivato l'oggetto remoto: "+this);
 }
 
 //protected void finalize() throws Throwable
 //{
 // System.out.println("Sono dentro il metodo finalize dell'oggetto attivabile. ");
 // System.out.println("finalize "+this);
 // super.finalize();
// }
 
//Implementazione del metodo remoto.
 public AcTrDate remAcTrDate()
   throws ActivationException, IOException, ClassNotFoundException
 {
  ActivationSystem as = ActivationGroup.getSystem();
   System.out.println("Ho ottenuto la seguente referenza al sistema di attivazione: "+as);
  ActivationID id = getID();
     System.out.println("Ho ottenuto il seguente ActivationID: "+id);
  ActivationDesc ad = as.getActivationDesc(id);
   System.out.println("E' stato costruito l' ActivationDescriptor: "+ad);
  Object object = ((MarshalledObject)ad.getData()).get();
  AcTrDate fatDate = (AcTrDate)object;
  int an = fatDate.getActNumber();
  int tn = fatDate.getTransNumber()+1;
  AcTrDate natDate = new AcTrDate(an,tn,new Date());
   System.out.println("Viene creato un oggetto AcTrDate: "+natDate);
  ActivationDesc nad = new ActivationDesc(ad.getGroupID(),ad.getClassName(),
                           ad.getLocation(), new MarshalledObject(natDate));
   System.out.println("E' stato costruito l' ActivationDescriptor: "+nad);
  ad = as.setActivationDesc(id,nad);
   System.out.println("Il vecchio ActivationDescriptor e' stato settato al seguente valore: "+ad);
  // Ok, queste righe sopra vanno riguardate sopra con attenzione nella documentazione API.
  return natDate;
 }
 
 public void unreferenced()
 {
  try
  {
   boolean ok = inactive(getID());
   System.out.println(" Sono dentro il metodo unreferenced dell'oggetto remoto " + this);
   System.out.println(" L'oggetto {"+this+"} e' inattivo? "+ok);
                 System.out.close();
   // Get myself collected
   System.gc();
   System.runFinalization();
  }
  catch (Exception e)
  {
   System.out.println("unreferenced: "+e);
                 System.out.close();
  }
 }
}


d) Il programma Setup.java per fare il set-up dell'oggetto: (NEW)

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;

//import javarmi.mytests.activation.datetime.AcTrDate;
//import javarmi.mytests.activation.datetime.RemActDateTime;
//import javarmi.mytests.activation.datetime.server.RemActDateTimeServer;

/**
 * Setup RMI servers to be Activatable.
 *
 * @author Esmond Pitt
 * @version $Revision: 2 $
 */
public final class Setup
{ static Remote remote;
  public Setup(String codebase) throws ActivationException,
                                       UnknownGroupException,
                                       RemoteException,
                                       MalformedURLException
 {
  // Tale comando invoca il costruttore della superclass, cioe Object.
  super();
  System.out.println("Sto eseguendo i comandi all'interno del costruttore di Setup");
  try
  {
  System.out.println("Cominciamo Con la registrazione del gruppo:");
     Properties properties = new Properties();
   properties.put("java.security.policy",System.getProperty("java.security.policy"));
   System.out.println("Le Properties sono state settate tramite: "+properties);
   System.out.println("Il codebase da dove verra' caricata la classe dell'oggetto attivabile e': "+codebase);
   System.out.println("Adesso creiamo un'istanza di tipo ActivationGroup,  usando il costruttore per ActivationDesc creiamo un descrittore di gruppo");
   ActivationGroupDesc.CommandEnvironment ace = null;
   ActivationGroupDesc groupDesc = new ActivationGroupDesc(properties,ace);
   System.out.println("Abbiamo costruito l' ActivationGroupDescriptor: "+groupDesc);
   System.out.println("Adesso registriamo il gruppo ed otteniamo il suo ID, cioe identificatore, che ci sewrvira' per registrare il server in quel gruppo");
   ActivationGroupID agi = ActivationGroup.getSystem().registerGroup(groupDesc);
   System.out.println("Il gruppo e' stato registrato con groupID= "+agi);
   MarshalledObject data = null;
   System.out.println("Iniziamo adesso la fase di registrazione del server attivabile.");
   ActivationDesc activationDesc = new ActivationDesc
    (
     agi,       // groupID
     RemActDateTimeServer.class.getName(), // nome della classe attivabile
     codebase,                             //codebase
     data
    );
   System.out.println("E' stato costruito l' ActivationDescriptor: "+activationDesc);
    System.out.println("Adesso attraverso il metodo Activatable.register si registra l'oggetto attivabile nel sistema di attivazione  e siottiene come risultato una referenza remota (cioe' uno stub) all'oggetto attivabile");
   remote = (Remote)Activatable.register(activationDesc);
   System.out.println("Ho registrato nel sistema di attivazione l'oggetto attivabile che puo' essere acceduto attraverso lo stub: "+"{"+remote+"}");
   // 6. Si lega lo stub ad un nome nel registro RMI
   System.out.println("Faccio il binding dello stub {"+remote+"}, relativo all'oggetto,  {"+RemActDateTime.class.getName()+"} nel registro RMI alla porta 1098 dove
    gia' si e' registrato il sistema di attivazione che e' esso stesso un oggetto. ");
   Naming.rebind("rmi://localhost:1098/"+RemActDateTime.class.getName(),remote);
  }
  finally
  {System.out.println("Sto uscendo dal costruttore di Setup.");
  }
 }
 
 public void test()
  throws IOException, NotBoundException, MalformedURLException,
         ActivationException, ClassNotFoundException
 {
  System.out.println("Faccio una lookup sul registro RMI alla porta 1098 per cercare l'oggetto {"+RemActDateTime.class.getName()+"}");
  RemActDateTime atDateServ =
  (RemActDateTime)Naming.lookup("rmi://localhost:1098/"
                               +RemActDateTime.class.getName());
  System.out.println("La lookup ha avuto successo ed ho ottenuto lo stub: {"+atDateServ +"}" );
  System.out.println("Adesso utilizzo lo stub per invocare il metodo remoto remAcTrDate dell'oggetto. Cio' causera' l'attivazione dell'oggetto, se questi non e' attivo.");
  AcTrDate atDate = atDateServ.remAcTrDate();
  System.out.println("Adesso stampo il risultato dell'invocazione remota");
  System.out.println("activation n. "+atDate.getActNumber()+", "+
                     "transaction n. "+atDate.getTransNumber()+", "+
                     "at remote date&time "+atDate.getTransDateTime()
                    );
 }

 // Main program
 public static void main(String args[])
 {
  String codebase;
  if (args.length > 0)
   codebase = args[0];
  else
  {
  //Verifica che il codebase e' stato settato da linea di comando
   codebase = System.getProperty("java.rmi.server.codebase");
   if (codebase == null)
  // Se non e' stato settato lo si fissa al valore del localhost.
    codebase = "http://localhost/";
  }
   System.out.println("Il codebase e': "+codebase);
  try
  {
   // NB different from tutorial which does it on the command line - why?
   System.setProperty("java.rmi.server.codebase",codebase);
   // Install a SecurityManager
   System.setSecurityManager(new RMISecurityManager());
   System.out.println("Mi accingo ad iniziare il Setup dell'attivazione.");
   Setup setup = new Setup(codebase);
   System.out.println("Il Set up e' terminato con successo.");
   System.out.println("Invoco il metodo test della classe Setup");
   setup.test();
    System.out.println("E' terminato il metodo test della classe Setup");
  }
  catch (Throwable t)
  {
   t.printStackTrace();
  }
  finally
  {
       System.out.println("Mi accingo a fare la garbage collection dal main del programma di Setup. Cio' causera' implicitamente l'invocazione del metodo unreferenced dell'oggetto attivabile con conseguente inattivazione dell'oggetto.");
       System.gc();
       System.out.println("Ho fatto la garbage collection dal main del programma di Setup.");
       System.runFinalization();
       System.out.println("Ho lanciato il metodo System.runFinalization()dal main del programma di Setup.");
       // 7. Quit
       System.out.println("Stiamo per lanciare il comando System.exit(0) dal main del programma di Setup per uscire dalla JVM.");
   System.exit(0);
  }
 }
}


e) mettete il file di policy in datetime visto che il sistema di attivazione effettua del caricamento dinamico di codice dall'area condivisa.


2) Compiliamo i sorgenti in datetime con javac *.java

3)  facciamo la compilazione rmic da activation facendo rmic -d public_html/myclasses/activation/ datetime.RemActDateTimeServer

4) Nota che l'implementazione del server, cioe' la classe RemActDateTimeServer.class, deve essere caricata dinamicamente dal sistema di attivazione quando
      si attiva l'oggetto attivabile. Per tale ragione spostiamo la sua classe, insieme alle classsi RemActDateTime.class e AcTrDate.class,  nel codebase
      public_html/myclasses/activation/ 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 la Setup. Tale classe non viene caricata dinamicamente.

5) Lanciamo dalla home directory il sistema rmid sostituendo codebase e indirizzo di policy opportun. Per comodita' lanciamo in una finestra differente del server.

 rmid -J-Djava.rmi.server.codebase=http://arena..../myclasses/activation/    
           -J-Djava.security.policy=/home/..../javarmi/activation/datetime/policy &


(NEW)
l'attivazione di rmid vi creera' una diretory su disco che si chiama  log,  li' dove avete lanciato rmid (ad esempio nella home). Tale directory di log conterra' i file di log
e conterra' le informazioni per riattivare oggetti attivabili registrati col sistema di attivazione. Poiche tale file e' persistente (e' scrittto su disco) gli oggetti attivabili sono
persistenti e possono essere riattivati anche dopo un reboot del server.

6) Lanciamo il programma di setup dalla directory activation in un altra finestra del server (notate che la classpath e' composta da DUE path).

java   -classpath /home...../javarmi/activation/:/home.../public_html/myclasses/activation/
         -Djava.rmi.server.codebase=http://arena...../myclasses/activation/
         -Djava.security.policy=/home/ .../javarmi/activation/datetime/policy
          datetime.Setup




- Se siete fortunati, nella finestra in cui e' stato lanciato il server, vi apparira'  una videata di questo tipo:

Il codebase e': http://profs.sci.univr.it/~merro/myclasses/activation/
Mi accingo ad iniziare il Setup dell'attivazione.
Sto eseguendo i comandi all'interno del costruttore di Setup
Cominciamo Con la registrazione del gruppo:
Le Properties sono state settate tramite: {java.security.policy=/export/home/docenti/merro/javarmi/activation/datetime/policy}
Il codebase da dove verra' caricata la classe dell'oggetto attivabile e': http://profs.sci.univr.it/~merro/myclasses/activation/
Adesso creiamo un'istanza di tipo ActivationGroup,  usando il costruttore per ActivationDesc creiamo un descrittore di gruppo
Abbiamo costruito l' ActivationGroupDescriptor: java.rmi.activation.ActivationGroupDesc@0
Adesso registriamo il gruppo ed otteniamo il suo ID, cioe identificatore, che ci sewrvira' per registrare il server in quel gruppo
Il gruppo e' stato registrato con groupID= java.rmi.activation.ActivationGroupID@bb8c5f8f
Iniziamo adesso la fase di registrazione del server attivabile.
E' stato costruito l' ActivationDescriptor: java.rmi.activation.ActivationDesc@3a615200
Adesso attraverso il metodo Activatable.register si registra l'oggetto attivabile e si ottiene come risultato, dal sistema di attivazione RMID, una referenza remota, cioe uno stub,  all'oggetto attivabile
Ho registrato nel sistema di attivazione l'oggetto attivabile che puo' essere acceduto attraverso lo stub: {datetime.RemActDateTimeServer_Stub[RemoteStub [ref: null]]}
Faccio il binding dello stub {datetime.RemActDateTimeServer_Stub[RemoteStub [ref: null]]}, relativo all'oggetto, {datetime.RemActDateTime} nel registro RMI alla porta 1098 dove gia' si e' registrato il sistema di attivazione che e' esso stesso un oggetto.
Sto uscendo dal costruttore di Setup.
Il Set up e' terminato con successo.
Invoco il metodo test della classe Setup
Faccio una lookup sul registro RMI alla porta 1098 per cercare l'oggetto {datetime.RemActDateTime}
La lookup ha avuto successo ed ho ottenuto lo stub: {datetime.RemActDateTimeServer_Stub[RemoteStub [ref: null]]}
Adesso utilizzo lo stub per invocare il metodo remoto remAcTrDate dell'oggetto. Cio' causera' l'attivazione dell'oggetto, se questi non e' attivo. (**)
Adesso stampo il risultato dell'invocazione remota
activation n. 1, transaction n. 1, at remote date&time Thu Jun 12 12:32:51 CEST 2003
E' terminato il metodo test della classe Setup
Mi accingo a fare la garbage collection dal main del programma di Setup. Cio' causera' implicitamente l'invocazione del metodo unreferenced dell'oggetto attivabile con conseguente inattivazione dell'oggetto. (***)
Ho fatto la garbage collection dal main del programma di Setup.
Ho lanciato il metodo System.runFinalization()dal main del programma di Setup.
Stiamo per lanciare il comando System.exit(0) dal main del programma di Setup per uscire dalla JVM.

- Mentre nella finestra in cui e' stato lanciato il sistema di attivazione RMID appare la seguente videata, dovuta al fatto che al punto (**) della schermata precedente
   viene invocato un metodeo dell'oggetto attivabile che causera l'attivazione dell'oggetto remoto.  Le ultime due righe sono generate dalla invocazione di garbage collection
fatta in Setup al punto (***).  Poiche' non vi sono referenze remote viene invocato il metodo unreferenced dell'oggetto remoto  chesi occupa di disattivare l'oggetto.
Tutto cio' viene registrato nella directory log.

 Thu Jun 12 16:11:18 CEST 2003:ExecGroup-0:out:Sono dentro il costruttore dell'oggetto remoto.
Thu Jun 12 16:11:18 CEST 2003:ExecGroup-0:out:Ho ottenuto la seguente referenza al sistema di attivazione: sun.rmi.server.Activation$ActivationSystemImpl_Stub[RemoteStub [ref: [endpoint:[157.27.252.10:1098](remote),objID:[0:0:0, 4]]]]
Thu Jun 12 16:11:18 CEST 2003:ExecGroup-0:out:E' stato costruito l' ActivationDescriptor: java.rmi.activation.ActivationDesc@3ee35200
Thu Jun 12 16:11:19 CEST 2003:ExecGroup-0:out:Ho attivato l'oggetto remoto: datetime.RemActDateTimeServer[RemoteStub [ref: [endpoint:[157.27.252.10:48125](local),objID:[1]]]]
Thu Jun 12 16:11:19 CEST 2003:ExecGroup-0:out:Ho ottenuto la seguente referenza al sistema di attivazione: sun.rmi.server.Activation$ActivationSystemImpl_Stub[RemoteStub [ref: [endpoint:[157.27.252.10:1098](remote),objID:[0:0:0, 4]]]]
Thu Jun 12 16:11:19 CEST 2003:ExecGroup-0:out:Ho ottenuto il seguente ActivationID: java.rmi.activation.ActivationID@bc5a5b0f
Thu Jun 12 16:11:19 CEST 2003:ExecGroup-0:out:E' stato costruito l' ActivationDescriptor: java.rmi.activation.ActivationDesc@eea65d2a
Thu Jun 12 16:11:19 CEST 2003:ExecGroup-0:out:Viene creato un oggetto AcTrDate: datetime.AcTrDate@35f53a
Thu Jun 12 16:11:19 CEST 2003:ExecGroup-0:out:E' stato costruito l' ActivationDescriptor: java.rmi.activation.ActivationDesc@a4249142
Thu Jun 12 16:11:19 CEST 2003:ExecGroup-0:out:Il vecchio ActivationDescriptor e' stato settato al seguente valore: java.rmi.activation.ActivationDesc@eea65d2a
Thu Jun 12 16:11:19 CEST 2003:ExecGroup-0:out: Sono dentro il metodo unreferenced dell'oggetto remoto datetime.RemActDateTimeServer[RemoteStub [ref: [endpoint:[157.27.252.10:48125](local),objID:[1]]]]
Thu Jun 12 16:11:19 CEST 2003:ExecGroup-0:out: L'oggetto {datetime.RemActDateTimeServer[RemoteStub [ref: [endpoint:[157.27.252.10:48125](local),objID:[1]]]]} e' inattivo? true



7) Studiate questi passi uno alla volta e comprendete esattamente cosa succede e perche'.

Fate anche il seguente esperimento. Dalla macchina client invocate la ListRegistry vista nella lezioni precedenti con parametro rmi://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' l'oggetto remoto attivabile datetime.RemActDateTime con referenza remota (cioe' stub) datetime.RemActDateTimeServer_Stub[RemoteStub [ref: null]].

8) Osservate che se spostate le classi dalla directory in public_html avrete problemi in fase di attivazione dell'oggetto attivabile che sa di dover caricare ogni volta le classi dall'area comune. E le classi a lui necessarie per partire non sono solo gli stub ma anche le classi dell'implementazione, dell'interfaccia, e quella su cui si basa l'interfaccia.



9) Passiamo a vedere il Client. Noi siamo interessati a caricamento dinamico del codice del client. Quindi mettiamo il codice del client sulla macchina del server.
     Piu precisamente, sempre nella directory javarmi/activation/datetime del server, mettiamo due files:

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.*;


/** client mobile Remote DateTime, con informazione di persistenza */


public class RemActDateTimeClient implements Runnable
{
 public void run()
 {
  try
  {
   System.out.println("IL Client ha inizio");
   System.out.println("Il Client invoca il metodo getServ di RemActDateTimeFactory per ottenere la referenza remota all'oggetto attivabile");
   RemActDateTime atDateServ = RemActDateTimeFactory.getServ();
   System.out.println("La referenza remota ottenuta e': "+atDateServ);
 System.out.println("Adesso invochiamo il metodo remoto dell'oggetto attivabile che causera' la sua attivazione,  se al momento e' inattivo.");
   AcTrDate atDate = atDateServ.remAcTrDate();
   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 (ricordatevi di sostituire 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
{
// - sostituire $SHOST con il nome dell'host server, sui cui si esegue
//   il setup e si lancia il sistema di attivazione rmid
// - sostituire $HOME con il valore che ha questa variabile nell'ambiente
//   di esecuzione
 
 public static final String reg = "rmi://profs.sci.univr.it:1098/";  // questa e' la locazione remota e la porta dove si trova il registro RMI
 static final String saveProt="file://";
 static final String saveRef="/home/massimo/.RemAcTrDateTimeRef"; //questo e' il file locale al client in cui memorizza la referenza remota.
 static RemActDateTime persRef = null;

 public static RemActDateTime getServ()
 throws IOException, NotBoundException,
    ClassNotFoundException, java.net.MalformedURLException
 {
  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("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 nel file .RemAcTrDateTimeRef, nella home, per successive invocazioni.");
  }
  return persRef;
 }
}



10) Compilate presso il server  in javarmi/activation/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 nuova area comune (possibilmente differente da quella del server). Ad esempio public_html/myclasses/client/datetime/
        dove supponiamo abbiate costruito le directory opportune (nota come l'area condivisa sia differente da quella usata dal server). Facciamo allora:

        mv RemActDateTime.class AcTrDate.class RemActDateTimeClient.class  RemActDateTimeFactory.class ~/public_html/myclasses/client/datetime/

12)  Nell'area condivisa ~/public_html/myclasses/client/datetime/  dobbiamo preoccupparci di copiare anche gli stub visto che il codebase del client sovrascrive quello del
         server.

13)  Andiamo adesso nella macchina Client. E mettiamo nella directory javarmi/activation/datetime il seguente codice minimale per il caricamento dinamico delle classi
         clienti:

14)  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
{
// - sostituire $USER con il valore che ha questa variabile nell'ambiente
//   di esecuzione

 static final String codebase = "http://profs.sci.univr.it/~merro/myclasses/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();
 }
}


15) Compiliamo il sorgente sopra indicato.

16) Aggiungiamo il file di policy nella directory datetime visto che vi e' il caricamento di codice dinamico.

17)  Lanciamo il client dalla directory activation con:

        java -Djava.security.policy=datetime/policy datetime.URLClientBootstrap

(NEW)

18) La prima volta che lo lanciate vi apparira' una videata del tipo:

IL CLient ha inizio
Il file .RemAcTrDateTimeRef dove memorizziamo la referenza all'oggetto attivabile NON e' stato trovato.
Facciamo allora una lookup sulla macchina remota per ottenere la referenza remota all'oggetto
Dopodiche' ci preoccupiamo di salvare la referenza remota nel file .RemAcTrDateTimeRef, nella home, per successive invocazioni.
Il Client ha invocato il metodo getServ di RemActDateTimeFactory ottenendo la referenza remota all'oggetto attivabile: datetime.RemActDateTimeServer_Stub[RemoteStub [ref: null]]
Adesso invochiamo il metodo remoto dell'oggetto attivabile che causera' la sua attivazione se al momento e' inattivo.
activation n. 2, transaction n. 2, at remote date&time Wed Jun 11 10:49:33 CEST 2003

-- L'utlima linea sta ad indicare che l'oggetto e' stato attivato due volte ed invocato due volte.

19)
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 esso viene attivato
ed appare la seguente videata:

Thu Jun 12 16:12:44 CEST 2003:ExecGroup-1:out:Sono dentro il costruttore dell'oggetto remoto.
Thu Jun 12 16:12:44 CEST 2003:ExecGroup-1:out:Ho ottenuto la seguente referenza al sistema di attivazione: sun.rmi.server.Activation$ActivationSystemImpl_Stub[RemoteStub [ref: [endpoint:[157.27.252.10:1098](remote),objID:[0:0:0, 4]]]]
Thu Jun 12 16:12:44 CEST 2003:ExecGroup-1:out:E' stato costruito l' ActivationDescriptor: java.rmi.activation.ActivationDesc@a4249142
Thu Jun 12 16:12:44 CEST 2003:ExecGroup-1:out:Ho attivato l'oggetto remoto: datetime.RemActDateTimeServer[RemoteStub [ref: [endpoint:[157.27.252.10:48147](local),objID:[1]]]]
Thu Jun 12 16:12:44 CEST 2003:ExecGroup-1:out:Ho ottenuto la seguente referenza al sistema di attivazione: sun.rmi.server.Activation$ActivationSystemImpl_Stub[RemoteStub [ref: [endpoint:[157.27.252.10:1098](remote),objID:[0:0:0, 4]]]]
Thu Jun 12 16:12:44 CEST 2003:ExecGroup-1:out:Ho ottenuto il seguente ActivationID: java.rmi.activation.ActivationID@bc5a5b0f
Thu Jun 12 16:12:44 CEST 2003:ExecGroup-1:out:E' stato costruito l' ActivationDescriptor: java.rmi.activation.ActivationDesc@bb5c0fba
Thu Jun 12 16:12:44 CEST 2003:ExecGroup-1:out:Viene creato un oggetto AcTrDate: datetime.AcTrDate@35f53a
Thu Jun 12 16:12:44 CEST 2003:ExecGroup-1:out:E' stato costruito l' ActivationDescriptor: java.rmi.activation.ActivationDesc@6ea17b8e
Thu Jun 12 16:12:44 CEST 2003:ExecGroup-1:out:Il vecchio ActivationDescriptor e' stato settato al seguente valore: java.rmi.activation.ActivationDesc@bb5c0fba


20)
Se lanciamo ancora il client, poiche il server e' ancora attivo non e' necessari riattivare l'oggetto. Per verificare che il server sia ancora attivo basta fare un ps sulla finestra di RMID e noterete che c'e' un processo java in esecuzione. Per l'appunto
il server attivabile.

-Notate anche che il client alla seconda invocazione ha avuto una videata leggermente differente, del tipo:

IL CLient ha inizio
Il Client invoca il metodo getServ di RemActDateTimeFactory per ottenere la referenza remota all'oggetto attivabile
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 invochiamo il metodo remoto dell'oggetto attivabile che causera' la sua attivazione,  se al momento e' inattivo.
activation n. 2, transaction n. 3, at remote date&time Thu Jun 12 12:43:59 CEST 2003

-Infatti la prima volta il client ha  cercato nella vostra home il file .RemAcTrDateTimeRef per otetnere la referenza remota all'oggetto attivabile. Tale file non esisteva ancora
  e quindi e' stata fatta fatta la lookup per ottenere la referenza che e' poi stata memorizzata  memorizzata nel file suddetto 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 file .RemAcTrDateTimeRef.

- 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.


21) Anche qui studiate attentamente il codice del client che viene caricato dinamicamente.

22) 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 causera' la cessazione del sistema di attivazione rmid, con la cessazione del processo rmid. Questo causa anchela cessazione
   del registro RMI alla porta 1098 come potete verificare rilanciando ListRegistry. Il quale dara' un'eccezione perche' non trova il registro.
   Se provate a rilanciare il Client a questo punto avrete un'eccezione perche' lo stub non trova il sistema di attivazione con cui interagire.

23) Se pero' rilanciate il sistema di attivazione rmid nel server, come fatto prima, allora potete rilanciare il client che invochera' il metodo remoto causando l'attivazione dell'oggetto remoto attivabile presso il server,  come apparira' nella finestra dove lanciato RMID. Notate che l'oggetto non e' piu' bound nel registro RMI alla porta 1098
(potete verificarlo con la Listregistry) ed il client funziona solo perche' prende la referenza remota all'oggetto dal file locale .RemAcTrDateTimeRef dove l'aveva memorizzata precedentemente. Inoltre il client ottiene l'informazione che adesso il server e' stato attivato per la terza volta. 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 all'oggetto remoto attivabile.
Dopo aver lanciato rmid,  invocate dal client la ListRegistry e noterete che vi 'e un solo elemento sul registro alla porta 1098 e cioe' il sistema di attivazione. Non vi e' piu' invece l'oggetto attivabile che era stato messo nel registro RMI dal programma di Setup.



24) Infine se lasciate l'oggetto attivabile  per un 'po di tempo (5-10 minuti) senza invocarlo,  lui si disattivera' da solo e sulla finestra di RMID apparira':

Thu Jun 12 13:23:12 CEST 2003:ExecGroup-0:out: Sono dentro il metodo unreferenced dell'oggetto remoto datetime.RemActDateTimeServer[RemoteStub [ref: [endpoint:[157.27.252.10:46682](local),objID:[1]]]]
Thu Jun 12 13:23:12 CEST 2003:ExecGroup-0:out: L'oggetto {datetime.RemActDateTimeServer[RemoteStub [ref: [endpoint:[157.27.252.10:46682](local),objID:[1]]]]} e' inattivo? true