niedziela, 3 października 2010

Mechanizm RMI (Remote Method Invocation) w praktyce cz. 2

W poprzedniej części tego artykułu zatytułowanej Mechanizm RMI (Remote Method Invocation) w praktyce cz. 1 pokaząłem jak napisać prostą aplikację typu klient / serwer. Teraz spróbujemy rozbudować tamten projekt tak, aby serwer wywoływał metody klienta. Nie jest to typowa sytuacja wykorzystania tego mechanizmu, ale jest to dobra sytuacja dydaktyczna. Jako kod bazowy będziemy korzystać z projektu przygotowanego w poprzedniej części kursu.

W projekcie klienta dodajmy zdalny interfejs:

package com.blogspot.mstachniuk.example.rmiclient;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface MyClientInt extends Remote {

    void showInfo(String info) throws RemoteException;
}

Nalezy pamiętać aby metody interfejsu deklarowały wyjątek RemoteException. W przeciwnym wypadku podczas tworzenia obiektu dostaniemy wyjatek: ExportException powodowany przez: IllegalArgumentException.

Stwórzmy dalej implementację tego interfejsu, analogicznie jak w poprzednim wpisie:

package com.blogspot.mstachniuk.example.rmiclient;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

public class MyClientImpl extends UnicastRemoteObject
        implements MyClientInt {

    private static final long serialVersionUID = 1L;

    public MyClientImpl() throws RemoteException {
        super();
    }

    @Override
    public void showInfo(String info) {
        System.out.println("Info: " + info);
    }
}

i dodajmy do MyClientMain linijki rejestrujące obiekt (zaraz po utworzeniu context'u):

MyClientImpl myClientImpl = new MyClientImpl();
context.bind("rmi:MyClientObject", myClientImpl);

Teraz należało by po stronie serwera napisać kod, który by wyołał metodę klienta. Dodajmy poniższy kod w metodzie getDescription(String text) klasy MyServerImpl tuż przed instrukcją return:

String url = "rmi://localhost/";
try {
    Context context2 = new InitialContext();
    MyClientInt myClientInt = (MyClientInt) 
            context2.lookup(url + "MyClientObject");
    myClientInt.showInfo("Info od serwera");
} catch(Exception e) {
    e.printStackTrace();
}

Wówczas gdy klient wywoła zdalną metodę getDescription() serwer wywoła metodę klienta i dopiero zwróci wynik do klienta. Nie jest to może najszczęśliwszy przykład, al chodzi tu o zaprezentowanie działania mechanizmu. Jako że serwer jest uruchamiany wcześniej niż kod klienta, to serwer musi poczekać na moment w którym zdalny obiekt klienta będzie już dostępny. Dlatego próbę wywołania zdalnej metody klienta umieściłem w metodzie getDescription().

No dobra, importujemy to czego potrzebuje nasz wklejony kod (swoją drogą Eclipse kilkakrotnie w tym momencie mi się zawiesiło) i kopiujemy odpowiednie interfejsy (tj. MyClientInt). Następnie uruchamiamy i otrzymujemy masę wyjątków po stronie klienta. Trzeba dodać do skryptu uruchamiającego informację o codebase:

-Djava.rmi.server.codebase=file:/D:/Java_programy/RMIClient/bin/

Teraz otrzymujemy dwa wyjątki - po stronie klienta AccessControlException, a po stronie serwera UnmarshalException, spowodowany przez EOFException.

Zmodyfikujmy więc spowrotem plik polityki client.policy w projekcie klienta, aby zezwolić na wszystko:

grant {
 permission java.security.AllPermission;
};

Uruchamiamy i działa:) Czyli zabezpieczenia nie pozwalały na odpowiednią komunikację. Chcąc ustawić tylko tyle ile musimy, powyższy plik musimy zmodyfikować w następujący sposób:

grant {
 permission java.net.SocketPermission
 "*:1024-65535", "connect, accept";
};

Napiszę jeszcze trochę o wyjątkach. W przypadku jabyśmy podali zły adres zdalnego obiektu otrzymalibyśmy  wyjątek javax.naming.NoInitialContextException. W przypadku gdy nazwa na zdalny obiekt jest zajęta (np. gdy odpalimy dwie instancje klienta), otrzymamy javax.naming.NameAlreadyBoundException. Istnieje jeszcze pewnie wiele sposobów aby coś zepsuć.

Jak widać technologia RMI daje możliwość łatwego wywoływania zdalnych metod w kodzie, tylko że trzeba się trochę namęczyć z całą otoczką uruchamiania tych aplikacji. Przedstawione tutaj rozwiązanie nie jest idealne, o czym napiszę w kolejnej części kursu.

Więcej informacji:
Mechanizm RMI (Remote Method Invocation) w praktyce cz. 1

Brak komentarzy:

Prześlij komentarz