Plik ten zawiera deklarację interfejsu, jaki będzie udostępniany odległym klientom. Ci klienci będą mogli jedynie odwoływać się do metod zadeklarowanych w tym interfejsie.
import java.rmi.*; public interface Matematyka extends Remote { int fib(int t) throws RemoteException; int ack(int m, int n) throws RemoteException; }
Plik ten zawiera deklarację klasy implementującej interfejs Matematyka. Obiekt tej klasy będzie służył jako serwer udostępniający zdalne usługi. Przykład ten jest rozszerzony o kilka pomocniczych metod raportujących stan serwera: wywołanie i zakończenie metod czy liczba uruchomionych wątków.
Ostatnia, statyczna metoda jest metodą służącą do utowrzenia i zarejestrowania utworzonego obiektu.
import java.rmi.*; import java.rmi.server.UnicastRemoteObject; public class MatematykaImpl extends UnicastRemoteObject implements Matematyka { public MatematykaImpl() throws RemoteException { super(); System.out.println("Nowy obiekt MatematykaImpl"); report(); } private void report(){ System.out.println("Liczba aktywnych watkow: " + Thread.activeCount()); System.out.println("nazwa watku: " + Thread.currentThread().getName()); } private int _fib(int n){ if (n < 2) return 1; else return _fib(n-1) + _fib(n-2); } public int fib(int n){ int res; System.out.println("Poczatek fib"); report(); res = _fib(n); System.out.println("Koniec fib"); return res; } private int _ack(int n, int m){ if (n == 0) return m + 1; else if(m == 0) return _ack(n - 1, 1); else return _ack(n - 1, _ack(n, m - 1)); } public int ack(int n, int m){ int res; System.out.println("Poczatek ack"); report(); res = _ack(n,m); System.out.println("Koniec ack"); return res; } public static void main(String arg[]){ //Utworzenie managera bezpieczenstwa if (System.getSecurityManager() == null) System.setSecurityManager(new RMISecurityManager()); try { MatematykaImpl obj = new MatematykaImpl(); Naming.rebind("//127.0.0.1/Wyklad", obj); System.out.println("Usluga zarejestrowana"); } catch (Exception e) { System.out.println("Usluga niezarejestrowana: " + e.getMessage()); } } }
Plik zawiera deklarację klienta korzystającego ze zdalnych usług. Konieczne jest tu wskazanie serwera, na którym uruchomiony jest program rmiregistry. Zwykle jest to ten sam serwer, na którym uruchomiony jest serwer usługowy.
import java.rmi.*; public class Klient { public static void main(String arg[]){ String server = "swiatowit"; Matematyka m = null; try { m = (Matematyka)Naming.lookup("//" + server + "/Wyklad"); System.out.println("Zdalny obiekt został odnaleziony"); // wywołania zdalnych metod System.out.println("fib 19: " + m.fib(19)); System.out.println("fib 20: " + m.fib(20)); System.out.println("fib 21: " + m.fib(21)); System.out.println("ack(3,3): " + m.ack(3,3)); } catch (Exception e) { System.out.println("Error: " + e.getMessage()); } } }
Po stronie serwera powinne być dwa pliki: Matematyka.java i MatematykaImpl.java. Kompilowane są standardowo:
javac *.javaNastępnie należy zbudować szkielet i przedstawiciela poleceniem
rmic MatematykaImplTworzone są wtedy dwa pliki: MatematykaImpl_Skel.class oraz MatematykaImpl_Stub.class. Kolejny krok to uruchomienie brokera RMI:
rmiregistry &i zarejestrowanie w nim usługi
java -Djava.security.policy=test.policy MatematykaImplPlik test.policy zawiera listę przywilejów, jakie nadajemy programom wykonywanym za pomocą tego wywołania maszyny wirtualnej. Jest on konieczny, gdyż domyślne prawa są zbyt restrykcyjne, aby zarejestrować usługę. Poniżej znajduje się przykładowy plik zezwalający na wszelkie operacje, dlatego w bardziej zaawansowanych aplikacjach wymagałby modyfikacji:
grant { permission java.security.AllPermission; };
Wymagane są dwa pliki źródłowe: Klient.java i Matematyka.java (ten sam, jak po stronie serwera). Konieczne jest też skopiowanie z serwera do klienta plik MatematykaImpl_Stub.class. Następnie uruchamiany jest klient poleceniem
java KlientNiekiedy potrzebne jest (w zależności od lokalnych ustawień) wskazanie pliku z prawami, podobnie jak w przypadku uruchomienia serwera. Plik test.policy z serwera powinien załatwić sprawę.
W przypadku tego typu serwerów procedura po stronie klienta wygląda tak samo. Trochę inaczej wygląda serwer (konstruktor) oraz procedura rejestracji.
import java.rmi.*; import java.rmi.activation.*; import java.util.Properties; public class MatematykaImpl extends Activatable implements Matematyka { // konstruktor // called by the method ActivationInstantiator.newInstance during // activation, to construct the object. // public MatematykaImpl(ActivationID id, MarshalledObject data) throws RemoteException { super(id, 0); System.out.println("Nowy obiekt MatematykaImpl"); report(); } ... }
Powyższy tekst zawiera jedynie deklarację klasy oraz konstruktor. Metody implementujące interfejs wyglądają identycznie jak powyżej. Inaczej natomiast wygląda metoda rejestracji obiektu:
public static void main(String arg[]) throws Exception { // Utworzenie managera bezpieczenstwa if (System.getSecurityManager() == null) System.setSecurityManager(new RMISecurityManager()); // Wskazanie pliku z prawami dla danej grupy Properties props = new Properties(); props.put("java.security.policy", "/home/..../test.policy"); ActivationGroupDesc.CommandEnvironment ace = null; ActivationGroupDesc exampleGroup = new ActivationGroupDesc(props, ace); // Rejestracja grupy i uzskanie identyfikatora ActivationGroupID agi = ActivationGroup.getSystem().registerGroup(exampleGroup); // Wskazanie katalogu zawierającego plik class z implementacją // serwera String location = "file:/home/.../activatable/"; // Argument dla konstruktora serwera MarshalledObject data = null; // Utorzenie środowiska dla pojedynczego obiektu ActivationDesc desc = new ActivationDesc (agi, "MatematykaImpl", location, data); // rejestracja w serwerze rmid Matematyka m = (Matematyka)Activatable.register(desc); System.out.println("Got the stub for the Matematyka"); // rejestracja w serwerze rmiregistry & try { System.out.println("Location: " + desc.getLocation()); Naming.rebind("Wyklad", m); System.out.println("Usluga zarejestrowana"); } catch (Exception e) { System.out.println("Usluga niezarejestrowana: " + e.getMessage()); } System.exit(0); }Oprócz uruchomienia serwera rmiregistry konieczne jest też uruchomienie serwera rmid:
rmid -J-Djava.security.policy=rmid.policy &W tym momencie można uruchomić rejesrację usługi, dokładnie tak jak poprzednio. Plik z prawami jest tu konieczny i może wyglądać następująco:
grant { permission com.sun.rmi.rmid.ExecPermission "/usr/local/java1.3.02/bin/java"; permission com.sun.rmi.rmid.ExecPermission "/usr/local/java1.3.02/bin/java_g"; permission com.sun.rmi.rmid.ExecPermission "/files/apps/rmidcmds/*"; permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.policy=/home/.../test.policy"; permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.debug=*"; permission com.sun.rmi.rmid.ExecOptionPermission "-Dsun.rmi.*"; };Trzeba pamiętać o ustawieniu odpowiednich ścieżek do plików wykonywalnych środowiska JAVA.