Java RMI

Tworzenie i udostępnianie zdalnych obiektów przejściowych oraz aktywowalnych.

Slajdy do wykładu

Slajdy w formacie PDF w układzie 1 sl./str., 2 sl./str., 3 sl./str., 4 sl./str., 6 sl./str.

Zadania laboratoryjne

Zadanie 1: licznik

  1. Zaimplementować i przetestować zdalny licznik, czyli obiekt udostępniający wartość całkowitą poprzez operacje getNext, getPrev i getCurr, zgodnie z poniższym interfejsem:

     import java.rmi.*;
    
     public interface Count extends Remote {
        int getNext() throws RemoteException;
        int getPrev() throws RemoteException;
        int getCurr() throws RemoteException;
    }
  2. “Spowolnić” operacje dostępu i sprowokować ich podzielność poprzez uśpienie wątku na kilka sekund i odpowiednie zdekomponowanie operacji zwiększania/zmniejszania z wykorzystaniem dodatkowej zmiennej lokalnej, np.:

    public int getNext() throws RemoteException {
       int v = value + 1;
       try {
          Thread.sleep(5000);
       }
       catch(Exception e){};
       value = v;
       return value;
    }
  3. Sprawdzić poprawność działania licznika poprzez uruchomienie kilku współbieżnie działających procesów/wątków.

  4. Zdefiniować (i przetestować) operacje dostępu do obiektu-licznika jako synchronized, np.:

    public synchronized int getNext() throws RemoteException {
       int v = value + 1;
       try {
          Thread.sleep(5000);
       }
       catch(Exception e){};
       value = v;
       return value;
    }
  5. Zdefniować własny rejestr po stronie serwera (zrezygnować z rmiregistry), np.:

    Registry r = LocateRegistry.createRegistry(6000);
    r.rebind(name, c1);

Uwagi

  • Konieczne jest zdefiniowanie pliku polityki bezpieczeństwa, np.:

    grant {
       permission java.security.AllPermission;
    };
  • Plik polityki bezpieczeństwa musi zostać podany przy uruchomieniu maszyny wirtualnej, np. w przypadku pliku o nazwie policy byłoby to:

    java -Djava.security.policy=policy Server
  • Jeśli rmiregistry uruchomione jest na innym porcie, po stronie klienta konieczne jest wsypecyfikowanie tego portu w URL’u z nazwą, np. "//localhost:6000/Counter".

  • Jeśli rmiregistry uruchomione jest w innym katalogu niż katalog zawierający pliki klas (z bajtkodem), to dla lokalizacji klas istotna jest własność codebase, którą należałoby zdefiniować przy uruchamianiu serwera. Zależnie od sposobu udostępniania i systemu operacyjnego byłoby to np.:

    -Djava.rmi.server.codebase=file:/home/inf29582/java/rmi/
    -Djava.rmi.server.codebase=http://sirius.cs.put.poznan.pl/~inf29582/java/rmi

Zadanie 2: bufor 1-elementowy

  1. Zaimplementować i przetestować zdalny bufor jednoelementowy z odpowiednią synchronizacją dostępu w celu przekazywania danych (buforowania na raz jednej jednostki) od dostawcy (producenta) do odbiorcy (konsumenta). Jako typ elementu przyjąć wybrany interfejs, np. IItem:

    public interface IItem extends java.io.Serializable {
    }

    W praktyce oznacza, że przekazywany pomiędzy dostawcą a odbiorcą może być dowolny obiekt klasy, implementującej ten interfejs, np.:

    public class Item implements IItem {
       public int i;
       public Item(int i){
          this.i = i;
       }
    }
    1. Bufor w wersji pull

      Odbiorca pobiera dane z bufora z własnej inicjatywy.

      Interfejs zdalnego bufora 1-elementowego:

      import java.rmi.*;
      
      public interface IBuffer extends Remote {
         public void put(IItem item) throws RemoteException;
         public IItem get() throws RemoteException;
      }

      Implementacja zdalnego bufora 1-elementowego:

      import java.rmi.*;
      import java.rmi.server.*;
      import java.rmi.registry.*;
      
      public class Buffer extends UnicastRemoteObject implements IBuffer {
         protected IItem buffered_item = null;
      
         Buffer() throws RemoteException {
            super();
         }
         
         public synchronized void put(IItem item) throws RemoteException {
            while(buffered_item != null)
               try {
                  this.wait();
               } catch(InterruptedException e){}
            buffered_item = item;
            this.notifyAll();
         }
         public synchronized IItem get() throws RemoteException {
            IItem item;
            while(buffered_item == null)
               try {
                  this.wait();
               } catch(InterruptedException e){}
            item = buffered_item;
            buffered_item = null;
            this.notifyAll();
            return item;
         }
      
         public static void main(String[] args) {
            if (System.getSecurityManager() == null) {
               System.setSecurityManager(new RMISecurityManager());
            }
            String name = "Buffer";
            try {
               Registry reg;
               reg = LocateRegistry.createRegistry(7701);
               Buffer buf = new Buffer();
               reg.rebind(name, buf);
               System.out.println("Buffer bound");
            } 
               catch (Exception e) {
                  System.err.println("Buffer exception: " + e.getMessage());
                  e.printStackTrace();
               }
         }
      }
    2. Bufor w wersji push

      Współdzielony bufor po otrzymaniu jednostki przekazuje ją do odbiorcy — wstawia do jego lokalnego bufora poprzez wywołanie zwrotne.

      Interfejs:

      import java.rmi.*;
      
      public interface IBufferCallBack extends IBuffer {
         public void register(IBuffer buf) throws RemoteException;
      }

      Implementacja:

      import java.rmi.*;
      import java.rmi.server.*;
      import java.rmi.registry.*;
      
      public class BufferCallBack extends Buffer implements IBufferCallBack {
         protected IBuffer client_buf = null;
      
         BufferCallBack() throws RemoteException {
            super();
         }
         
         public synchronized void put(IItem item) throws RemoteException {
            if ( client_buf == null )
               super.put(item);
            else
               try {
                  client_buf.put(item);
                  buffered_item = null;
               } catch(RemoteException e){
                  super.put(item);
                 }
         }
         public synchronized void register(IBuffer buf) throws RemoteException {
            client_buf = buf;
            if (buffered_item != null)
               try {
                  client_buf.put(buffered_item);
                  buffered_item = null;
               } catch(RemoteException e){}
         }
      
         public static void main(String[] args) {
            if (System.getSecurityManager() == null) {
               System.setSecurityManager(new RMISecurityManager());
            }
            String name = "Buffer";
            try {
               Registry reg;
               reg = LocateRegistry.createRegistry(7701);
               Buffer buf = new BufferCallBack();
               reg.rebind(name, buf);
               System.out.println("Buffer bound");
            } 
               catch (Exception e) {
                  System.err.println("Buffer exception: " + e.getMessage());
                  e.printStackTrace();
               }
         }
      }

      Przykład odbiorcy, współpracującego z buforem typu push:

      import java.rmi.*;
      
      class ConsumerCallBack {
         public static void main(String[] args){
            String name1 = "Buffer";
            String name2 = "//unixlab.cs.put.poznan.pl:7701/" + name1;
            try {
               IBuffer local_buf = new Buffer();
               IBufferCallBack remote_buf = (IBufferCallBack) Naming.lookup( name2 );
               remote_buf.register(local_buf);
               Item i;
               i = (Item)local_buf.get();
               System.out.println( "Pobrano: " + i.i );
            }
                catch(Exception e){
                  System.err.println( "Consumer exception: " + e.getMessage() );
                  e.printStackTrace();
               }
         }
      }

Spis treści

Poprzedni temat

Sun RPC

Następny temat

JMS/OpenMQ

Ta strona