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