Технологія Java Remote Method Invocation (Java RMI)
Завантажити презентаціюПрезентація по слайдам:
Зміст Спрощена архітектура RMI. Особливості програмування RMI/JRMP-проектів. Активація RMI-об'єктів. Демон активації rmid. Віддалені інтерфейси та класи реалізації віддалених інтерфейсів. Порівняння RMI/JRMP та RMI/IIOP. “Експортування” об'єктів. Статичний метод ExportObject. RMI/IIOP-проекти. Використання rmic та orbd. RMI
Платформа J2EE. Механізми та служби Взаємодія з клієнтом: JSP (Java Server Pages). Java сервлети. Web-служби. Бізнес-логіка: Enterprise Java Beans (EJB). (Специфікація EJB є серцевиною платформи J2EE). Базові служби (інтерфейси API): JNDI JTS JPA JTA JDBC RMI RMI/IIOP Java IDL JCA JMS JavaMail JAF У J2EE пропонується широкий спектр інтерфейсів API для уніфікованого доступу до сервісів (служб) та програм, реалізованих сторонніми організаціями RMI
Поняття про служби іменування Клієнт Сервер Служба іменування 1: реєстрація (публікація) - з іменем 2: пошук - за іменем 3: . . . RMI
Використання "служби іменування RMI/JRMP” (RMI- реєстратора) для зв'язувань з віддаленими об'єктами Проблема отримання посилань на віддалені об'єкти (проблема отримання “найпершого” посилання на один із віддалених об'єктів) “RMI-імена” RMI-реєстратор за замовчуванням використовує порт 1099 rmi:// [:] / RMI
Особливості програмування RMI/JRMP-проектів: 1) використання "служби іменування" (" RMI-реєстратора"); 2) визначення віддалених інтерфейсів, успадкованих від Remote; 3) розробка класів реалізації для визначених віддалених інтерфейсів; 4) урахування можливості Remote-виключень (RemoteException): при визначенні інтерфейсних функцій та кожного метода з класу реалізації треба передбачити використання конструкції throws; при визначенні конструкторів (у тому числі конструкторів за замовчуванням) також треба передбачити використання конструкції throws. interface Remote не містить жодного метода, є ярликом, “візиткою” об'єктів із передачею by Reference 1 2 3 4 RMI
До угоди про іменування (суфікси) складових частин RMI/JRMP-проектів MyInterface – віддалений інтерфейс; MyInterfaceImpl – клас реалізації; MyInterfaceImpl_Stub – клас-проксі (у вигляді байт-коду з розширенням class). Він призначений як для клієнтської частини (так звана заглушка), так і для серверної (так званий скелетон). Цей клас генерується (при наявності файлів MyInterface.class, MyInterfaceImpl.class) утилітою (Java RMI компілятором) rmic: (Для останніх версій JDK генерація стаб-класів шляхом запуску rmic вимагається не завжди – див. проект “02 NoStub”). MyInterfaceServer – клас-сервер; MyInterfaceClient – клас-клієнт. rmic MyInterfaceImpl Зауваження. На відміну від Java 2 (SDK 1.2) у SDK 1.1 використовувався окремий клас-скелетон (клас-каркас) MyInterfaceImpl_Skel. RMI
Приклад. Віддалений інтерфейс Sm та клас реалізації SmImpl public interface Sm extends java.rmi.Remote { float add(float arg1, float arg2) throws Exception; } public class SmImpl extends java.rmi.server.UnicastRemoteObject implements Sm{ public SmImpl() throws Exception { super(); // не обов'язково (за замовчуванням) } public float add(float arg1, float arg2) throws Exception { return (arg1 + arg2); } } визначення віддалених інтерфейсів, успадкованих від Remote урахування можливості Remote-виключень (RemoteException) конструктор за замовчуванням метод розробка класів реалізації для визначених віддалених інтерфейсів 2 3 4 RMI
Приклад. Java-модулі SmServer та SmClient import java.rmi.Naming; public class SmServer { public SmServer() { try { Sm sm = new SmImpl(); Naming.rebind("rmi://localhost:1099/SmService", sm); } catch (Exception e) { System.out.println("Fail: " + e); } } public static void main(String args[]) { new SmServer(); } } import java.rmi.Naming; public class SmClient { public static void main(String[] args) { try { Sm sm = (Sm)Naming.lookup("rmi://localhost/SmService"); System.out.println( sm.add(1, 2) ); } catch (Exception e) { System.out.println("Fail: " + e); } } } використання "служби іменування” (" RMI- реєстратора") Віддалений інтерфейс Віддалений об'єкт “RMI-імена” 1 SmServer.java SmClient.java Віддалений інтерфейс RMI
Послідовність запусків RMI-системи типу клієнт-сервер(хост) При створенні об'єкта, що є дочірнім від UnicastRemoteObject запускається на невизначений час окремий потік, завдяки чому програма-сервер перебуває у “стані очікування” підключень клієнтів rmiregistry [port] (Rmi-реєстр запускається як окремий процес, за замовчуванням використовується порт 1099). Зауважимо, що є можливість створення Rmi-реєстру (як об'єкта) безпосередньо програмою-сервером (проте, звичайно, лише на серверному вузлі). java SmServer java SmClient Запускається хост-сервер, “експонується” об'єкт, до якого можуть звертатись клієнти RMI
Програмне створення RMI-реєстру на серверному вузлі Також можна програмно (після виконання одного з варіантів метода LocateRegistry.getRegistry) отримувати безпосереднє посилання на “конкретний” RMI-реєстр (за зазначеними вузлом та/або портом). import java.rmi.Naming; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; public class SmServerR { public SmServerR() { try { Registry r = LocateRegistry.createRegistry(1099); Sm sm = new SmImpl(); Naming.rebind("rmi://localhost:1099/SmService", sm); } catch (Exception e) { System.out.println("Fail: " + e); } } public static void main(String args[]) { new SmServerR(); } } RMI
Статичний метод ExportObject та (JRMP - IIOP) портабельність Java RMI-проектів ExportObject “Експортування” об'єктів 1 2 Експортування надає об'єкту здатність приймати віддалені виклики RMI
Використання об'єктних параметрів та/або результатів. Серіалізація. (1/3) Клієнт Сервер LocOb - серіалізовуваний клас LocOb getLocOb() Клієнт Віддалений інтерфейс interface Serializable не містить жодного метода, є ярликом, “візиткою” об'єктів з передачею by Value RMI
Використання об'єктних параметрів та/або результа-тів. Серіалізація. (2/3) Client Host Віддалений інтерфейс Конструктор. Створення об'єкта lo . Саме він буде передаватись клієнту конструктор класу LocOb метод класу LocOb Реалізація Серіалізований клас LocOb RMI
Використання об'єктних параметрів та/або результатів. Серіалізація. (3/3) Client Серіалізовуваний клас Метод get_a() виконується у клієнтській програмі RMI
Використання посилань (віддалених об'єктів) як параметрів та/або результатів (1/4) GetRemOb getRemOb = (GetRemOb) Naming.lookup("rmi://localhost:1099/Server"); Sm gsm = getRemOb.getSm(); System.out.println( gsm.add(3,3) ); Client.java SmServer “уміє” додавати - add() Server “знає”, як “дістатись” до SmServer RMI
Використання посилань (віддалених об'єктів) як параметрів та/або результатів (2/4) GetRemOb getRemOb = (GetRemOb) Naming.lookup("rmi://localhost:1099/Server"); Sm gsm = getRemOb.getSm(); System.out.println( gsm.add(3,3) ); public interface GetRemOb extends java.rmi.Remote { Sm getSm() throws Exception; } public interface Sm extends java.rmi.Remote { float add(float arg1, float arg2) throws Exception; } Client Server Client.java Віддалений інтерфейс Sm SmServer Віддалений інтерфейс GetRemOb 1) gsm=getRemOb.getSm(); 2) gsm.add(3,3); У конструкторі: 1) sm = … lookup …; 2) sm.add(2,2); RMI
Використання посилань (віддалених об'єктів) як параметрів та/або результатів (3/4) import java.rmi.Naming; public class Server extends java.rmi.server.UnicastRemoteObject implements GetRemOb { Sm sm; public Server() throws Exception { super(); try { sm = (Sm)Naming.lookup("rmi://localhost:1099/SmService"); System.out.println("Server as client(SmServer) : calls add(2,2)"); System.out.println(sm.add(2,2)); } catch (Exception e) { System.out.println("Server: Fail - " + e); } } public Sm getSm() throws Exception { return sm; } public static void main(String args[]) { try { GetRemOb getRemOb = new Server(); Naming.rebind("rmi://localhost:1099/Server", getRemOb); } catch (Exception e) { System.out.println("Fail1: " + e); } } } Server.java public class SmImpl extends java.rmi.server.UnicastRemoteObject implements Sm{ public SmImpl() throws Exception { } public float add(float arg1, float arg2) throws Exception { System.out.println("Adding " + arg1 +" + " + arg2); return (arg1 + arg2); } } Client.java RMI
Активація RMI-об'єктів. Демон активації rmid (1/2) Активація об'єктів здійснюється за запитами клієнтів, проте абсолютно прозоро (!) для клієнтів. Суть проблеми полягає у тому, щоб фактично відкласти створення об'єктів до отримання запитів (це обумовлює специфіку конструкторів та й об'єктів у цілому). Кілька штрихів: java-клас найчастіше успадковується від Activatable (альтернатива – “експортування” об'єктів шляхом застосування статичного метода Activatable.exportObject); створюється дескриптор активації desc (з урахуванням імені, місцезнаходження класу, даних ініціалізації об'єкта): ActivationDesc desc=new ActivationDesc(agi,"TestImpl",location,data); дескриптор активації “реєструється у rmid ” з виробленням заглушки: TestI ti = (TestI)Activatable.register(desc); отримана заглушка фіксується у rmiregistry: Naming.rebind("ActivImpl", ti); демон активації rmid “перехоплює” запити та активізує потрібний об'єкт, використовуючи для цього окрему JVM. RMI
Активація RMI-об'єктів. Демон активації rmid (2/2) Додатково треба враховувати використання менеджерів безпеки. Зауважимо, що JVM містить інстальований менеджер безпеки, та й сам запуск rmid , як правило, спряжений з визначенням файлу політики безпеки: rmid -J-Djava.security.policy=rmid.policy (тут опція -J означає, що відповідний параметр “політики безпеки” передається JVM, яка власне запускає демон rmid). Файлом політики безпеки демону rmid надається дозвіл (ExecPermission) на запуск (чи використання запущеної) JVM. Дозвіл ExecOptionPermission загалом пов'язаний з можливістю використання опцій у запусках з командного рядка. Наведемо ще один приклад: permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.policy=c:\\. . .\\policies\\group.policy"; grant { permission com.sun.rmi.rmid.ExecPermission "c:\\Program Files\\Java\\jdk1.6.0\\bin\\java"; permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.policy=*"; }; rmid.policy RMI
Активація RMI-об'єктів. Послідовність запусків rmiregistry rmid -J-Djava.security.policy=rmid.policy java -Djava.security.policy=forall.policy Setup java Client Client rmid Звернімо увагу на те, що Setup , відпрацювавши, “закривається”. Прозорість активаціЇ RMI
Активація RMI-об'єктів. Приклад (1/2) import java.rmi.*; import java.rmi.activation.* ; import java.io.*; public class TestImpl extends Activatable implements TestI { /**@param id the activation id @param data the marshalled construction parameter */ public TestImpl(ActivationID id, MarshalledObject data) throws RemoteException { // Register the object with the activation system // then export it on an anonymous port super(id, 0); System.out.println("inside constructor TestImpl"); } public String SayOK() throws RemoteException { System.out.println("Inside SayOK"); return "OK !!!"; } } import java.rmi.*; public interface TestI extends Remote { String SayOK() throws RemoteException; } grant { permission java.security.AllPermission; }; public static void main(String[] args){ try { TestI ti = (TestI)Naming.lookup("rmi://localhost/ActivImpl"); System.out.println(ti.SayOK()); } Віддалений інтерфейс (TestI.java) Клас реалізації віддаленого інтерфейсу (TestImpl.java) Client.java (фрагмент) RMI
Активація RMI-об'єктів. Приклад (2/2) import java.rmi.*; import java.rmi.activation.*; import java.util.Properties; import java.io.*; public class Setup { public static void main(String args[]){ try{ System.setSecurityManager(new RMISecurityManager()); System.out.println("activation descriptor..."); // Because of the Java 2 security model, a security policy should // be specified for the ActivationGroup VM Properties props = new Properties(); props.put("java.security.policy", "c:/java/07_Activatable/forall.policy"); //The same JVM (rmid) for Activation: ActivationGroupDesc.CommandEnvironment ace = null; ActivationGroupDesc exampleGroup = new ActivationGroupDesc(props, ace); // Once the ActivationGroupDesc has been created, register it // with the activation system to obtain its ID ActivationGroupID agi = ActivationGroup.getSystem().registerGroup(exampleGroup); // The "location" String specifies a URL from where the class // definition will come when this object is requested (activated). // Don't forget the trailing slash at the end of the URL // or your classes won't be found. String location = "file:/c:/java/07_Activatable/"; // Create the rest of the parameters that will be passed to // the ActivationDesc constructor MarshalledObject data = null; // The location argument to the ActivationDesc constructor will be used // to uniquely identify this class; it's location is relative to the // URL-formatted String, location. ActivationDesc desc= new ActivationDesc(agi,"TestImpl",location,data); TestI ti = (TestI)Activatable.register(desc); System.out.println("Got the stub for the ActivatableImplementation"); Naming.rebind("ActivImpl", ti); System.out.println("Exported ActivatableImplementation"); System.out.println("Exiting... " ) ; System.exit(0); } catch(Exception e){ e. printStackTrace (); } } } grant { permission com.sun.rmi.rmid.ExecPermission "c:\\Program Files\\Java\\jdk1.6.0\\bin\\java"; permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.policy=*"; }; grant { permission java.security.AllPermission; }; rmid.policy forall.policy Setup.java Можна вилучити, оскільки у даному прикладі об'єкти створюються віртуальною машиною демона активації RMI
Проекти RMI/JRMP та RMI/IIOP у порівнянні технологія RMI/IIOP використовує “повноцінну” (у відповідності з CORBA-специфікацією) службу іменування orbd. (Можна використовувати й “застарілу”, проте також цілком “повноцінну” службу іменування tnameserv); властивості класів реалізації віддалених інтерфейсів для RMI/IIOP-проектів забезпечуються успадкуванням від PortableRemoteObject, а не від UnicastRemoteObject. 1 3 Відмінності у програмуванні стосуються лише пунктів 1) – та 3) – 1 3 RMI
Порівняння RMI/JRMP та RMI/IIOP. Віддалені інтерфейси та класи реалізації віддалених інтерфейсів RMI
RMI/IIOP-проекти. Приклад. Віддалений інтерфейс Sm та клас реалізації SmImpl public interface Sm extends java.rmi.Remote { float add(float arg1, float arg2) throws Exception; } public class SmImpl extends java.rmi.server. PortableRemoteObject implements Sm{ public SmImpl() throws Exception { super(); // не обов'язково (за замовчуванням) } public float add(float arg1, float arg2) throws Exception { return (arg1 + arg2); } } визначення віддалених інтерфейсів, успадкованих від Remote урахування можливості Remote-виключень (RemoteException) конструктор за замовчуванням метод розробка класів реалізації для визначених віддалених інтерфейсів 2 3 4 RMI
Порівняння проектів RMI/JRMP та RMI/ IIOP (віддалений інтерфейс Sm та клас реалізації SmImpl) Єдина відмінність: замість UnicastRemoteObject – PortableRemoteObject RMI
Статичний метод ExportObject. На шляху до (JRMP – IIOP) портабельності Java RMI-проектів (1/3) UnicastRemoteObject.ExportObject(MyOb... PortableRemoteObject.ExportObject(MyOb... Віддалений інтерфейс Клас реалізації віддаленого інтерфейсу ExportObject(MyOb... ExportObject(MyOb... JRMP IIOP Загальна частина RMI
Статичний метод ExportObject. На шляху до (JRMP – IIOP) портабельності Java RMI-проектів (2/3) ExportObject Загальна частина RMI
Статичний метод ExportObject. На шляху до (JRMP –IIOP) портабельності Java RMI-проектів (3/3) public class SmPImpl implements Sm{ public SmPImpl() throws Exception {} public float add(float arg1, float arg2) throws Exception { return (arg1 + arg2); }} public interface Sm extends java.rmi.Remote { float add(float arg1, float arg2) throws Exception; } SmPImpl obj = new SmPImpl(); Sm stub = (Sm)UnicastRemoteObject.exportObject(obj); Naming.bind("rmi://localhost/SmJRMP", stub); SmPImpl.java Sm.java SmPImpl obj = new SmPImpl(); PortableRemoteObject.exportObject(obj); Sm stub = (Sm)obj; Context ctx = new InitialContext(); ctx.rebind("SmIIOP", stub); SmPImpl.java HostSmJRMP.java (фрагмент) HostSmIIOP.java (фрагмент) Context ic = new InitialContext(); Object objref = ic.lookup("SmIIOP"); Sm sm = (Sm)PortableRemoteObject.narrow( objref, Sm.class); System.out.println( sm.add(1, 2) ); Sm sm = (Sm)Naming.lookup( "rmi://localhost/SmJRMP"); System.out.println( sm.add(1, 2) ); ClientSmJRMP.java (фрагмент) ClientSmIIOP.java (фрагмент) Не змінювані модулі Віддалений інтерфейс Клас реалізації віддаленого інтерфейсу Загальна частина RMI
RMI/IIOP-проекти. Java-модулі SmServer та SmClient import javax.naming.InitialContext; import javax.naming.Context; public class SmServer { public SmServer() { try { Sm sm = new SmImpl(); Context initialNamingContext = new InitialContext(); initialNamingContext.rebind("SmService", sm ); } catch (Exception e) { System.out.println("Fail: " + e); } } public static void main(String args[]) { new SmServer(); } } import javax.rmi.PortableRemoteObject; import javax.naming.InitialContext; import javax.naming.Context; public class SmClient { public static void main(String[] args) { try { Context ic = new InitialContext(); Object oref = ic.lookup("SmService"); Sm sm = (Sm) PortableRemoteObject.narrow(oref, Sm.class);; System.out.println( sm.add(1, 2) ); } catch (Exception e) { System.out.println("Fail: " + e); } } } Використовується API JNDI (Java Naming and Directory Interface) – “універсальна” служба імен та каталогів Віддалений інтерфейс Віддалений об'єкт Віддалений інтерфейс SmServer.java SmClient.java orbd -ORBInitialPort 1050 RMI
Порівняння проектів RMI/JRMP та RMI/ IIOP (Java-модулі SmServer та SmClient) Ключова відмінність: використовується API JNDI (Java Naming and Directory Interface) – “універсальна” служба імен та каталогів використовується "RMI-реєстратор" RMI
RMI/IIOP-проекти. Використання rmic та orbd. Послідовність запусків rmic -iiop CalcImplPortable orbd -ORBInitialPort 1050 (“постійна” служба іменування, забезпечується “зворотна” сумісність із застарілою “тимчасовою” службою іменування tnameserv) java -Djava.naming.factory.initial = com.sun.jndi.cosnaming.CNCtxFactory -Djava.naming.provider.url = iiop://localhost:1050 HostIIOP java -Djava.naming.factory.initial = com.sun.jndi.cosnaming.CNCtxFactory -Djava.naming.provider.url = iiop://localhost:1050 CalcClientIIOP - параметри (змінні), що забезпечують налаштування JNDI на конкретну реалізацію цього API (конкретну службу іменування) – тут orbd. 1 2 1, 2 1 2 orbd є повноцінною (у відповідності зі стандартом CORBA) службою іменування RMI
Деякі опції Java RMI компілятора rmic, призначені для RMI/JRMP -проектів -v1.2 (за замовчуванням) – генеруються тільки stub-класи для stub-протоколів JRMP 1.2 (для JVM версії 1.2 та версій, старших за 1.2); -v1.1 – генеруються stub- та skeleton-класи для stub-протоколів JRMP 1.1 (при використанні JVM 1.1); -vcompat – генеруються stub- та skeleton-класи, сумісні з обома версіями stub-протоколів JRMP 1.1 та 1.2. (У версіях JDK до 1.5 ця опція була за замовчуванням). rmic -vcompat MyInterfaceImpl RMI
Динамічне копіювання класів Аналогія з аплетами. Копіювання клієнтами (у першу чергу) чи серверами stub-класів: stub-класи можуть бути просто відсутні у клієнта; може змінюватись віддалений інтерфейс, при цьому змінюється і stub-клас. Копіювання клієнтами (так само і серверами!) класів, що є успадкованими від класів, представлених у віддалених методах як типи параметрів чи результатів. … foo(Class1 arg1) throws … Метод віддаленого інтерфейсу Серверна частина Клієнтська частина Можлива потреба у визначенні класу Class2 RMI
Динамічне копіювання класів. Властивість codebase Значення властивості codebase автоматично “приписується” віддаленому об'єкту при реєстрації останнього (у RMI registry). RMI
Копіювання (завантаження) stub-класів. Приклад з використанням http-сервера ClassFileServer java ClassFileServer 2001 c:\java\06_codebase\download rmiregistry (запуск здій java -Djava.rmi.server.codebase=http://localhost:2001/ SmServer java SmClient Властивість (property) JVM Stub-клас може виявитись потрібним як клієнту, так і серверу. У випадку об'єктних параметрів можуть передаватись об'єкти успадкованих класів. Такі класи необхідно завантажувати. (Завантаження успадкованих класів може бути необхідним як на боці клієнта, так і на боці сервера). RMI
Копіювання (завантаження) stub-класів. Приклад з використанням http-сервера ClassFileServer java ClassFileServer 2001 c:\java\06_codebase\download rmiregistry java -Djava.rmi.server.codebase=http://localhost:2001/ SmServer java SmClient Властивість (property) JVM RMI
Приклад зміненого rmid.policy та запуску Setup grant { permission com.sun.rmi.rmid.ExecPermission "c:\\Program Files\\Java\\jdk1.6.0\\bin\\java"; permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.policy=*"; }; rmid.policy Вилучено RMI
Схожі презентації
Категорії