Java RMI

HelloWorld

  1. Utworzyć plik z interfejsem programu HelloWorld
    import java.rmi.Remote;
    import java.rmi.RemoteException;
                                    
    public interface HelloWorld extends Remote {
          String getString(String name) throws RemoteException;
    }
    
  2. Napisać aplikację klienta odwołującego się do zdalnego obiektu implementującego interfejs HelloWorld:
    • rejestr, w którym zarejestrowany został zdalny obiekt znajduje się pod adresem wskazanym przez prowadzącego
    • program klienta pobiera z rejestru referencję na zdalny obiekt korzystając z metody Naming.lookup(String name);
    • program klienta wywołuje zdalną metodę getString jako argument podając tekst pobrany z linii komend przy uruchamianiu programu
    • napis zwrócony przez metodę getString należy wypisać na standardowe wyjście
    • skompilować program klienta
      javac *.java
    • utworzyć plik client.policy z definicją polityk bezpieczeństwa
      grant {
        permission java.security.AllPermission;
      };
    • uruchomić program klienta
      java -Djava.security.policy=client.policy HelloWorldClient
  3. Napisać własną implementację serwera HelloWorld
    • przygotować klasę HelloWorldObj rozszerzający klasę UnicastRemoteObject oraz implementujący interfejs HelloWorld
    • przygotować klasę HelloWorldServer, która w metodzie main utworzy instancję klasy HelloWorldObj, a następnie zarejestruje ten obiekt w rejestrze przy użyciu metody:
      Naming.rebind("//127.0.0.1:2100/HelloWorld")
    • skompilować program
    • uruchomić rejestr RMI
      rmiregistry nr_portu
    • uruchomić i przetestować serwer
      java -Djava.rmi.server.hostname=127.0.0.1 -Djava.security.policy=server.policy HelloWorldServer
  4. Przerobić program serwera tak, aby uruchamiał swój własny rejestr
    Registry registry = LocateRegistry.createRegistry(2100);
    registry.rebind("HelloWorld", obj);

Przekazywanie obiektów przez wartość i przez referencję

  1. Zaimplementować klasę ArgumentObject zawierającą prywatne pole value typu int oraz metody umożliwiające odczyt i nadpisanie wartości tego pola. Klasa powinna implementować interfejs java.io.Serializable
  2. Umieścić implementację ArgumentObject w classpath klienta i serwera
  3. Przerobić implementację HelloWorldObj, tak aby metoda getString przyjmowała jako argument obiekt klasy ArgumentObject, odczytywała wartość zdefiniowanego w tej klasie pola, nadpisywała wartość tego pola i zwracała odczytaną wcześniej wartość w postaci obiektu typu String
  4. Przerobić program klienta, tak aby tworzył obiekt ArgumentObject i podawał go jako argument wywołania metody getString ze zdalnego obiektu HelloWorldObj; następnie klient powinien wypisać odczytany String oraz aktualną wartość pola value z klasy ArgumentObject
  5. Sprawdzić rezultat działania programu
  6. Przerobić program, tak aby ArgumentObject przekazywany był przez referencję; w tym celu należy:
    • zdefiniować interfejs Argument rozszerzający interfejs Remote i umieścić go w classpath serwera i klienta,
    • przerobić implementację ArguentObject, tak aby rozszerzał UnicastRemoteObjet oraz implementował interfejs Argument,
    • usunąć klasę ArgumentObject z classpath serwera
  7. Uruchomić program i zaobserwować zmiany w działaniu

RemoteComputation

Zadanie: przygotować program umożliwiający wykonywanie po stronie serwera dowolnych obliczeń zleconych przez klienta:

  1. Serwera udostępnia zdalny obiekt implementujący interfejs Compute
    public interface Compute {
      Object runTask(Task task, Args args);
    }
  2. Task jest interfejsem reprezentującym zadanie obliczeniowe, posiada metodę run(Args args), która jest wywoływana wewnątrz metody runTask
  3. Klient dostarcza co najmniej dwie implementacje interfejsu Task, np. wykonujące dodawanie i mnożenie; obie klasy muszą implementować interfejs Serializable
  4. Klient korzystając z rejestru pobiera referencję na zdalny obiekt Compute i wywołuje metodę runTask podając jako argument jedną z implementacji interfejsu Task; wynik zwrócony przez runTask jest wypisywany na standardowe wyjście
  5. Klient dostarcza serwerowi klasy z implementacją Task poprzez http lub system plików, przykładowe wywołanie programu klienta wygląda wówczas następująco:
    java -Djava.rmi.server.codebase=file:///path/to/Task/implementation/ -Djava.security.policy=client.policy ComputeClient

Accounts

Zadanie: zaimplementować program do zdalnego wykonywania operacji na kontach bankowych

  1. Serwer udostępnia zdalny obiekt umożliwiający pobranie listy kont bankowych
    public interface AccountList extends Remote {
          List getList() throws RemoteException;
    }
  2. Interfejs Account rozszerza interfejs Remote i umożliwia przeprowadzenie podstawowych operacji na koncie
    public interface Account extends Remote {                                                                                                                                         
          public Integer getBalance() throws RemoteException; //pobranie stanu konta
          public Integer add(Integer amount) throws RemoteException; //dodanie określonej kwoty do stanu konta
          public Integer withdraw(Integer amount) throws RemoteException; //pobranie określonej kwoty z konta
    }
    
  3. Klient korzystając ze zdalnego obiektu implementującego AccountList pobiera listę zdalnych referencji na obiekty typu Account
  4. Do wybranego konta klient dopisuje określoną kwotę i sprawdza aktualny stan tego konta
  5. Sprawdzenie, czy modyfikacja stanu konta zapamiętywana jest między kolejnymi uruchomieniami programu klienta