Tworzenie i udostępnianie zdalnych obiektów przejściowych oraz aktywowalnych.
Slajdy w formacie PDF w układzie 1 sl./str., 2 sl./str., 3 sl./str., 4 sl./str., 6 sl./str.
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;
}
“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;
}
Sprawdzić poprawność działania licznika poprzez uruchomienie kilku współbieżnie działających procesów/wątków.
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;
}
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
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;
}
}
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();
}
}
}
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();
}
}
}