Esercizio 5: Mobilita' di Codice 

Caricamento del codice Client attraverso codebase da una macchina Server. 


Vediamo tre possibili esercizi in conformita' con quanto studiato sulla mobilita' di codice.
Si crei dentro javarmi un package mobility:

1) Bootstrap via RMIClassloader. 

Utilizzeremo una classe Client.class  da caricare dinamicamente presso un URL della macchina server, accessibile dalla macchina Client.


1.a) Si metta il seguente codice Client.java (gentilmente fornito dal vistro collega GiuLio:

package mobility;
import java.io.*;

public class Client implements Runnable, Serializable
{
public void run()
{
System.out.println("Io sono il Client caricato dinamicamente");
try
{
System.out.println("ora scrivo su prova.txt");
BufferedWriter out = new BufferedWriter(new FileWriter("prova.txt"));
out.write("ciaociao");
out.close();
System.out.println("Ora leggo da prova.txt");
BufferedReader in = new BufferedReader(new FileReader("prova.txt"));
String c = in.readLine();
System.out.println(c);
in.close();
}
catch (Exception ex)
{
System.out.println(ex.getMessage());
}
}
}


in un'area condivisa presso la macchina server, ad esempio dentro ~/public_html/common/mobility/
(creiamo un package mobility dentro l'area comune).

1.b) Si compili tale classe.

1.c) Nella macchina client si metta dentro la directory javarmi/mobility/ il codice del Client che si
preoccupa di caricare dinamicamente la sua classe, chiamato URLClientBootstrap.java:

package mobility;
import java.io.*;
import java.net.*;
import java.rmi.server.*;

public class URLClientBootstrap {
  static final String codebase = ".......";
  //mettete l'URL della vostra area comune: http://....
  static final String clientClass = "mobility.Client";

  public static void main(String[] args) throws Exception {
       System.setSecurityManager(new SecurityManager());
       Class classClient = RMIClassLoader.loadClass(codebase,clientClass);
       Runnable client = (Runnable)classClient.newInstance();
       client.run();
 }
}

d) Compilate il codice sopra indicato e lanciatelo dalla macchina client preoccupandovi di
 aggiungere nella directory javarmi/mobility/ della macchina Client il file di policy, visto
 che caricate dinamicamente del codice, ovvero quello della classe Client.class.

e) Lanciate il codice URLClientBootstrap dalla macchina client:

    java -Djava.security.policy=policy  mobility.URLClientBootstrat

f) Ricavate adesso l'insieme dei permessi necessari al vostro codice lanciando:

   java -Djava.security.policy=policy -Djava.security.debug=access,failure  mobility.URLClientBootstrat

IMPORTANTE1:
I permessi indicati col debug sono spesso ridondanti. Create il vostro
file di policy aggiungendo i permessi in seguenza:
1) Mettete  prima i socket permession, se il programma richiede altri permessi,
2) Guardate se  fate usa di file permission, eveutualmente aggiungete runtime permssione e
execOtion permission.

IMPORTANTE2:  se invece di -Djava.security.policy=policy scrivete -Djava.security.policy==policy con 2 segni '=' allora
si in tende che va utilizzato solo il file di policy dell'applicazione e trascurati gli altri file di policy


g) Una volta ricavati i permessi costruite il file di policy aiutandovi con il policytool
lanciando policytool -file policy  ( guardate per esempio http://javaalmanac.com/egs/java.security/CreatePolicy.html )
e rilanciate il codice con il file di policy costruito e con la clausola di debug.
Il policytool vi aiuta a costruire un file di policy evitando di mettere due volte un permesso.
Ovviamente non dovete mettere dei permessi che sono gia nel file di policy di sistema.

Per piu' dettagli sui policy files potete dare un'occhiata a:

http://javaalmanac.com/egs/java.security/UsePolicy.html
http://java.sun.com/j2se/1.5.0/docs/guide/security/PolicyFiles.html
http://www.oreilly.com/catalog/javasec2/chapter/ch01.html


h) Il vostro file di policy dovra' avere sostanzialmente la seguente struttura:

grant codebase "file///home/massimo/..../javarmi/-"                (Codebase da dove proviene il vostro codice mobility.URLClientBootstrap)
   { File permission di lettura e scrittura sul file in question;
      Socket permission di connect e resolve per connettersi al codebase dove risiede la classe Client.class
    }
grant codebase "http://delta...sci.univr.it:8000/common/"        (Codebase da dove proviene il vostro codice mobility.Client)
    {File permission di lettura e scrittura sul file in questione;
     }

Notate come il file permission sia necessario su tutti e due i codebase. Questo perche' la lettura e scrittura
e' fatta Client dopo che questa e' stata lanciata da URLClientBoostrap,  la quale sara'
nella pila d'attivazione sotto Client.class. Ne consegue che anche URLClientBootstrap deve
possedere tale diritto.  

h) Una volta creato il file di policy, provate a lanciare il codice con la proprieta' di debug
con flag differenti (riguardate gli appunti aggiornati della lezione).

2) Bootstrapping attraverso RMI

In questa soluzione il Server crea un oggetto di tipo Client e lo passa come risultato di
un'invocazione remota di un metodo di un oggetto remoto che viene registrato normalmente
nel registro RMI. Come sappiamo l'oggetto di tipo Client che verra passato deve essere
Serializzabile,
ed infatti la classe Client e' definita serializzabile. Il Client, dal canto suo fara'
una lookup per ottenere lo stub all'oggetto remoto in modo da invocare il metodo remoto
getClient() per ottenere un oggetto di tipo Client che verra' lanciato dalla sua macchina.


a) Nella macchina server si crea  dentro javarmi/mobility/si mette l'interfaccia del server Bootstrap.java:

package mobility;

import java.io.*;
import java.net.*;
import java.rmi.*;
import java.rmi.server.*;

public interface Bootstrap extends Remote  {
      Runnable getClient() throws RemoteException;
}


b) Si mette poi il codice del server, BootstrapServer.java:

package mobility;
import java.io.*;
import java.net.*;
import java.rmi.*;
import java.rmi.server.*;


class BootstrapServer extends UnicastRemoteObject implements Bootstrap {
    public BootstrapServer() throws RemoteException    {}
    public Runnable getClient()   { return new Client(); }
    public static void    main(String[] args) throws Exception {
        Bootstrap  server = new BootstrapServer();
        System.out.println("Il Server di Bootsrap e' stato lanciato.");
        Naming.rebind("BootServer",server);
        System.out.println("Il Server di Bootstrap e' stato registrato nel registro RMI.");
    }
}

c) Si aggiunge anche in javarmi/mobility/il codice Client.java sopra indicato.
 
d) Si va in javarmi/mobility/ e si compila il codice mettendo le classi nell'area comune:
 
         javac Bootstrap.java Client.java BootstrapServer.java

avendo cura di spostare la classe del client, Client.class,  nell'area del codebase (dentro il package mobility).

e) Si fa la compilazione rmic in javarmi con

          rmic -d ~/public_html/common/  mobility.BootstrapServer

     
e) Si lancia il registro RMI (corrrettamente) alla porta standard.

f) Si lancia il server dalla directory javarmi , ad esempio col seguente comando

java   -classpath :/....../public_html/common/
          -Djava.rmi.server.codebase=......../common/
           mobility.BootstrapServer

(notate che non ho aggiunto il file di policy).
 
g) Se tutto e' ok, vi spunta una schermata che dice:

Il  Server di Bootsrap e' stato lanciato.
Il Server di Bootstrap e' stato registrato nel registro RMI.



h) Nel client nella directory javarmi/mobililty/ si mette il file di policy, l'interfaccia
Bootstrap.java e RMIClientBootstrap.java con il seguente codice:

package mobility;
import java.io.*;
import java.net.*;
import java.rmi.*;
import java.rmi.server.*;

public class RMIClientBootstrap {
    static final String bootstrapServer = "//profs.sci.univr.it/BootServer";
    public static void main(String[] args) throws Exception {
        System.setSecurityManager(new SecurityManager());
        System.out.println("Il client si accinge a fare la  lookup");
        try {
              Bootstrap  bootstrap = (Bootstrap)Naming.lookup("//......../BootServer");
              System.out.println("Il client si accinge ad invocare il metodo getClient() del server ricavato dal registro RMI.");
              Runnable  client = bootstrap.getClient();
              System.out.println("Il client ha ottenuto un'istanza della classe Client e la lancia");
              client.run();
          }
         catch (RemoteException e) {
             System.err.println(e);
          }
     }
}

i) compilate il cliente in javarmi/mobility/ con

    javac Bootstrap.java RMIClientBootstrap.java

l) Lanciate il Client da javarmi non dimenticando la clausola di policy.

m) Anche in questo caso lanciate il client con la clausola di debug in modo da derivare i permessi necessari alla sua
 esecuzione e costruire il file di policy relativo.