Spec-Zone .ru
спецификации, руководства, описания, API
|
Это учебное руководство показывает Вам шаги, чтобы следовать, чтобы создать распределенную версию классики "Привет Мировая" программа, используя Java™ Удаленный Вызов метода (RMI) по интернет-Протоколу Межшара (IIOP). IIOP RMI добавляет CORBA (Общая Архитектура Посредника запросов к объектам) возможность к связи Java ко многим другим языкам программирования и платформам. Включения IIOP RMI распределяли удаленную Группу управления Веб-поддерживающего Java. Компоненты времени выполнения включают ШАР Java для распределенных вычислений, используя передачу IIOP.
IIOP RMI для программистов Java, которые хотят программировать к интерфейсам RMI, но IIOP использования как базовый транспорт. IIOP RMI предоставляет функциональной совместимости другие объекты CORBA, реализованные на различных языках - но только если все удаленные интерфейсы первоначально определяются как Java интерфейсы RMI. Это особенно интересно к Предприятию использования программистов JavaBeans (EJB), так как модель удаленного объекта для EJBs основана на RMI.
Другая опция для того, чтобы создать распределенные приложения является IDL Java™. IDL Java для программистов CORBA, которые хотят программировать в языке программирования Java, основанном на интерфейсах, определенных в Языке определения интерфейсов CORBA (IDL). Это - "обычный бизнес" программирование CORBA, поддерживая Java точно таким же образом как другие языки как C++ или КОБОЛ.
Распределенный Привет Мировой пример использует клиентское приложение, чтобы сделать удаленный вызов метода через IIOP к серверу, работая на узле, с которого был загружен клиент. Когда клиент работает, "Привет Мир!" выводится на экран.
Это учебное руководство организуется следующим образом:
Есть три задачи завершиться в этом разделе:
HelloInterface.java
- удаленный интерфейсHelloImpl.java
- реализация удаленного объекта, которая реализует HelloInterface
HelloServer.java
- сервер RMI, который создает экземпляр реализации удаленного объекта и связывает тот экземпляр с именем в Службе ИменованияHelloClient.java
- клиентское приложение, которое вызывает удаленный метод, sayHello()
Remote
интерфейс. Ваш удаленный интерфейс объявит каждый из методов, которые требуется вызвать от других машин. У удаленных интерфейсов есть следующие характеристики: public
. Иначе, клиент получит ошибку, пытаясь загрузить удаленный объект, который реализует удаленный интерфейс, если тот клиент не находится в том же самом пакете как удаленный интерфейс.java.rmi.Remote
интерфейс.java.rmi.RemoteException
(или суперкласс RemoteException
) в throws
пункт, в дополнение к любым специализированным исключениям.HelloInterface
) не класс реализации (HelloImpl
).Для этого примера создайте все исходные файлы в том же самом каталоге, например, $HOME/mysrc/RMIHelloPOA
. Вот интерфейсное определение для удаленного интерфейса, HelloInterface
. Интерфейс содержит только один метод, sayHello
:
//HelloInterface.java import java.rmi.Remote; public interface HelloInterface extends java.rmi.Remote { public void sayHello() throws java.rmi.RemoteException; }
java.rmi.RemoteException
. Если Вы хотите больше информации об отказе и восстановлении в распределенных системах, можно хотеть считать Как минимум, класс реализации удаленного объекта, HelloImpl.java
должен:
HelloImpl.java:
//HelloImpl.java import javax.rmi.PortableRemoteObject; public class HelloImpl extends PortableRemoteObject implements HelloInterface { public HelloImpl() throws java.rmi.RemoteException { super(); // invoke rmi linking and remote object initialization } public void sayHello() throws java.rmi.RemoteException { System.out.println( "It works! Hello World!!" ); } }
В языке программирования Java, когда класс объявляет, что это реализует интерфейс, контракт формируется между классом и компилятором. Заключая этот контракт, класс обещает, что это обеспечит тела метода, или определения, для каждых из сигнатур методов, объявленных в том интерфейсе. Интерфейсные методы неявно public
и abstract
, так, если класс реализации не выполняет свой контракт, это становится по определению abstract
класс, и компилятор укажут на этот факт, если класс не был объявлен abstract
.
Класс реализации в этом примере HelloImpl
. Класс реализации объявляет, какой удаленный интерфейс (ы) он реализует. Вот HelloImpl
объявление класса:
public class HelloImpl extends PortableRemoteObject implements HelloInterface{Как удобство, класс реализации может расширить удаленный класс, который в этом примере является
javax.rmi.PortableRemoteObject
. Расширяясь PortableRemoteObject
, HelloImpl
класс может использоваться, чтобы создать удаленный объект, который использует основанный на IIOP транспорт для передачи.
Кроме того, экземпляр удаленного объекта должен будет быть "экспортирован". Экспорт удаленного объекта делает доступным, чтобы принять входящие удаленные запросы метода, прислушиваясь к входящим вызовам к удаленному объекту на анонимном порту. Когда Вы расширяетесь javax.rmi.PortableRemoteObject
, Ваш класс будет экспортироваться автоматически после создания.
Поскольку объектный экспорт мог потенциально бросить a java.rmi.RemoteException
, следует определить конструктора, который бросает a RemoteException
, даже если конструктор не делает ничего иного. Если Вы забываете конструктора, javac
произведет следующее сообщение об ошибке:
HelloImpl.java:3: unreported exception java.rmi.RemoteException; must be caught or declared to be thrown. public class HelloImpl extends PortableRemoteObject implements HelloInterface{ ^ 1 errorРассмотреть: класс реализации для удаленного объекта нуждается к:
java.rmi.RemoteException
HelloImpl
класс: public HelloImpl() throws java.rmi.RemoteException { super(); }Отметьте следующее:
super
вызов метода вызывает конструктора без параметров javax.rmi.PortableRemoteObject
, который экспортирует удаленный объект.java.rmi.RemoteException
, потому что попытка RMI экспортировать удаленный объект во время конструкции могла бы перестать работать, если коммуникационные ресурсы не доступны.java.rmi.RemoteException
проверенное исключение, не исключение на этапе выполнения.
Хотя звонок в конструктора суперкласса без параметров, super()
, происходит по умолчанию (даже если опущенный), это включается в этот пример, чтобы ясно дать понять факт, что суперкласс будет создан перед классом.
sayHello()
метод, который возвращает строку "Это, работает! Привет Мир!!" к вызывающей стороне: public void sayHello() throws java.rmi.RemoteException { System.out.println( "It works! Hello World!!" ); }Параметры, или возвращаемые значения от, удаленные методы могут быть любым типом данных для платформы Java, включая объекты, пока те объекты реализуют интерфейс
java.io.Serializable
. Большинство базовых классов в java.lang
и java.util
реализуйте Serializable
интерфейс. В RMI: static
или transient
.rmic
генерировать тупики и скелеты.Класс сервера является классом, у которого есть a main
метод, который создает экземпляр реализации удаленного объекта, и связывает тот экземпляр с именем в Службе Именования. Класс, который содержит это main
метод мог быть классом реализации непосредственно, или другим классом полностью.
В этом примере, main
метод является частью HelloServer.java
, который делает следующее:
HelloServer.java:
//HelloServer.java
import javax.naming.InitialContext;
import javax.naming.Context;
import javax.rmi.PortableRemoteObject ;
//Please note that internal Sun APIs
//may change in future releases.
import com.sun.corba.se.internal.POA.POAORB;
import org.omg.PortableServer.*;
import java.util.*;
import org.omg.CORBA.*;
import javax.rmi.CORBA.Stub;
import javax.rmi.CORBA.Util;
public class HelloServer {
public HelloServer(String[] args) {
try {
Properties p = System.getProperties();
// add runtime properties here
//Please note that the name of the servertool
//class may change in future releases.
p.put("org.omg.CORBA.ORBClass",
"com.sun.corba.se.internal.POA.POAORB");
p.put("org.omg.CORBA.ORBSingletonClass",
"com.sun.corba.se.internal.corba.ORBSingleton");
ORB orb = ORB.init( args, p );
POA rootPOA = (POA)orb.resolve_initial_references("RootPOA");
// STEP 1: Create a POA with the appropriate policies
Policy[] tpolicy = new Policy[3];
tpolicy[0] = rootPOA.create_lifespan_policy(
LifespanPolicyValue.TRANSIENT );
tpolicy[1] = rootPOA.create_request_processing_policy(
RequestProcessingPolicyValue.USE_ACTIVE_OBJECT_MAP_ONLY );
tpolicy[2] = rootPOA.create_servant_retention_policy(
ServantRetentionPolicyValue.RETAIN);
POA tPOA = rootPOA.create_POA("MyTransientPOA", null, tpolicy);
// STEP 2: Activate the POA Manager, otherwise all calls to the
// servant hang because, by default, POAManager will be in the
// HOLD state.
tPOA.the_POAManager().activate();
// STEP 3: Instantiate the Servant and activate the Tie, If the
// POA policy is USE_ACTIVE_OBJECT_MAP_ONLY
HelloImpl helloImpl = new HelloImpl();
_HelloImpl_Tie tie = (_HelloImpl_Tie)Util.getTie( helloImpl );
String helloId = "hello";
byte[] id = helloId.getBytes();
tPOA.activate_object_with_id( id, tie );
// STEP 4: Publish the object reference using the same object id
// used to activate the Tie object.
Context initialNamingContext = new InitialContext();
initialNamingContext.rebind("HelloService",
tPOA.create_reference_with_id(id,
tie._all_interfaces(tPOA,id)[0]) );
System.out.println("Hello Server: Ready...");
// STEP 5: Get ready to accept requests from the client
orb.run();
}
catch (Exception e) {
System.out.println("Problem running HelloServer: " + e);
e.printStackTrace();
}
}
public static void main(String args[]) {
new HelloServer( args );
}
}
main
метод сервера сначала должен создать Переносимый Объектный Адаптер (POA) с соответствующими политиками. Например: Policy[] tpolicy = new Policy[3]; tpolicy[0] = rootPOA.create_lifespan_policy( LifespanPolicyValue.TRANSIENT ); tpolicy[1] = rootPOA.create_request_processing_policy( RequestProcessingPolicyValue.USE_ACTIVE_OBJECT_MAP_ONLY ); tpolicy[2] = rootPOA.create_servant_retention_policy( ServantRetentionPolicyValue.RETAIN); POA tPOA = rootPOA.create_POA("MyTransientPOA", null, tpolicy);
Переносимый Объектный Адаптер (POA) разрабатывается, чтобы обеспечить объектный адаптер, который может использоваться с многократными реализациями ШАРА с минимумом необходимой перезаписи, чтобы иметь дело с реализациями различных поставщиков. Поддержка POA была представлена в версии 1.4 J2SE.
POA также предназначается, чтобы позволить персистентные объекты - по крайней мере, с точки зрения клиента. Таким образом, насколько клиент заинтересован, эти объекты всегда живы, и поддерживают значения данных, сохраненные в них, даже при том, что физически, сервер, возможно, был перезапущен много раз, или реализация может быть обеспечена многими различными объектными реализациями.
POA позволяет объектному конструктору намного больше управления. Ранее, реализация объекта была ответственна только за код, который выполняется в ответ на запросы метода. Теперь, дополнительно, конструктор имеет больше контроля над идентификационными данными объекта, состоянием, хранением, и жизненным циклом.
В этом примере значения политики включают:
LifespanPolicyValue
может иметь следующие значения: TRANSIENT
- Объекты, реализованные в POA, не могут пережить экземпляр POA, в котором они сначала создаются.PERSISTENT
- Объекты, реализованные в POA, могут пережить процесс, в котором они сначала создаются.RequestProcessingPolicyValue
может иметь следующие значения: USE_ACTIVE_OBJECT_MAP_ONLY
- Если объектный ID не находится в Активной Объектной Карте, OBJECT_NOT_EXIST
исключение возвращается клиенту. RETAIN
политика также требуется.USE_DEFAULT_SERVANT
- Если объектный ID не находится в Активной Объектной Карте или NON_RETAIN
политика присутствует, и слуга по умолчанию был зарегистрирован в POA использование set_servant
работа, запрос диспетчеризируется слуге по умолчанию.USE_SERVANT_MANAGER
- Если объектный ID не находится в Активной Объектной Карте или NON_RETAIN
политика присутствует, и менеджер слуги был зарегистрирован в POA использование set_servant_manager
работа, менеджеру слуги дают возможность определить местоположение слуги или повысить исключение.ServantRetentionPolicyValue
может иметь следующие значения. RETAIN
- указать, что POA сохранит активных слуг в своей Активной Объектной Карте. Если нет ServantRetentionPolicy
определяется при создании POA, значение по умолчанию RETAIN
.NON_RETAIN
- чтобы указать на Слуг не сохраняются POA.Для получения дополнительной информации по политикам POA сошлитесь на Главу 11, Переносимый Объектный Адаптер CORBA/IIOP 2.3.1 Спецификации в
У каждого объекта POA есть связанное POAManager
объект. Менеджер POA может быть связан с одним или более объектами POA. Менеджер POA инкапсулирует состояние обработки POAs, с которым оно связывается. В этом шаге активируется менеджер POA. Если этот шаг отсутствует, все звонки Servant
завис бы, потому что по умолчанию менеджер POA будет в HOLD
состояние.
tPOA.the_POAManager().activate();
main
метод сервера должен создать экземпляр реализации удаленного объекта, или Слугу. Например: HelloImpl helloImpl = new HelloImpl();Конструктор экспортирует удаленный объект, что означает, что когда-то создаваемый, удаленный объект готов принять входящие вызовы.
При использовании технологии IIOP RMI Ваши реализации используют делегацию (известный как модель Связи), чтобы связать Вашу реализацию с интерфейсом. Когда Вы создаете экземпляр своей реализации, как выше, Вы также должны создать объект Связи связать ее с интерфейсом CORBA. Следующие немного строк кода активируют Связь, но только если политика POA USE_ACTIVE_OBJECT_MAP_ONLY
.
_HelloImpl_Tie tie = (_HelloImpl_Tie)Util.getTie( helloImpl ); String helloId = "hello"; byte[] id = helloId.getBytes(); tPOA.activate_object_with_id( id, tie );
Как только удаленный объект регистрируется на сервере, вызывающие стороны могут искать объект по имени (использующий службу именования), получить ссылку удаленного объекта, и затем удаленно вызвать методы на объект. В этом примере мы используем Демона Посредника запросов к объектам (orbd
), который является процессом демона, содержащим Службу Начальной загрузки, Переходную Службу Именования, Персистентную Службу Именования, и Диспетчер серверов.
Например, следующий код связывает имя "HelloService" со ссылкой для удаленного объекта:
Context initialNamingContext = new InitialContext(); initialNamingContext.rebind("HelloService", tPOA.create_reference_with_id(id, tie._all_interfaces(tPOA,id)[0]) ); System.out.println("Hello Server: Ready...");
Отметьте неотступно следование за параметрами rebind
вызов метода:
"HelloService"
, a java.lang.String
, представление имени удаленного объекта, чтобы связатьtPOA.create_reference_with_id(id, tie._all_interfaces(tPOA,id)[0]
объектный идентификатор удаленного объекта, чтобы связатьorb.run();
Клиентское приложение в этом примере удаленно вызывает sayHello
метод, чтобы получить строку "Привет Мир!" чтобы вывести на экран, когда клиентское приложение работает. Вот код для клиентского приложения:
//HelloClient.java import java.rmi.RemoteException; import java.net.MalformedURLException; import java.rmi.NotBoundException; import javax.rmi.*; import java.util.Vector; import javax.naming.NamingException; import javax.naming.InitialContext; import javax.naming.Context; public class HelloClient { public static void main( String args[] ) { Context ic; Object objref; HelloInterface hi; try { ic = new InitialContext(); } catch (NamingException e) { System.out.println("failed to obtain context" + e); e.printStackTrace(); return; } // STEP 1: Get the Object reference from the Name Service // using JNDI call. try { objref = ic.lookup("HelloService"); System.out.println("Client: Obtained a ref. to Hello server."); } catch (NamingException e) { System.out.println("failed to lookup object reference"); e.printStackTrace(); return; } // STEP 2: Narrow the object reference to the concrete type and // invoke the method. try { hi = (HelloInterface) PortableRemoteObject.narrow( objref, HelloInterface.class); hi.sayHello(); } catch (ClassCastException e) { System.out.println("narrow failed"); e.printStackTrace(); return; } catch( Exception e ) { System.err.println( "Exception " + e + "Caught" ); e.printStackTrace( ); return; } } }
Во-первых, клиентское приложение получает ссылку на реализацию удаленного объекта (рекламируемый как "HelloService") от службы имен, используя Интерфейс Именования и Каталога Java [ТМ] (JNDI) вызовы. Как Naming.rebind
метод, Naming.lookup
метод берет java.lang.String
значение, представляющее имя объекта искать. Вы предоставляете Naming.lookup() имя объекта, который Вы хотите искать, и это возвращает объект, связанный с тем именем.
_HelloImpl_Stub
экземпляр, связанный с тем именемlookup
метод получает удаленный объект (HelloImpl
) тупиковый экземпляр и загрузки тупиковый класс (_HelloImpl_Stub
)Naming.lookup
возвращает тупик его вызывающей стороне (HelloClient
)sayHello()
метод на удаленном объекте сервера, вызывая строку "Это работает! Привет Мир!!" чтобы быть выведенным на экран на командной строке.HelloInterface.java
содержит исходный код для удаленного интерфейсаHelloImpl.java
содержит исходный код для реализации удаленного объектаHelloServer.java
содержит исходный код для сервераHelloClient.java
содержит исходный код для клиентского приложенияHelloImpl.java
, чтобы создать .class
файлы должны были работать rmic
. Вы тогда работаете rmic
компилятор, чтобы создать тупики и скелеты. Тупик является прокси клиентской стороны для удаленного объекта, который вперед IIOP RMI призывает к диспетчеру серверной стороны, который поочередно вперед звонок в фактическую реализацию удаленного объекта. Последняя задача состоит в том, чтобы скомпилировать остающееся .java
исходные файлы, чтобы создать .class
файлы. Следующие задачи будут завершены в этом разделе:
rmic
генерировать тупики и скелетыСоздать тупик и скелетные файлы, rmic
компилятор должен быть выполнен на полностью определенных именах пакета скомпилированных файлов класса, которые содержат реализации удаленного объекта. В этом примере файл, который содержит реализации удаленного объекта, HelloImpl.java
. Чтобы генерировать тупики и скелеты, мы должны сначала скомпилировать HelloImpl.java
, следующим образом:
javac -d . -classpath . HelloImpl.java
"-d .
"опция указывает, что сгенерированные файлы должны быть помещены в каталог, из которого Вы выполняете компилятор."-classpath .
"опция указывает на это файлы на который HelloImpl.java
зависит может быть найден в этом каталоге.
rmic
генерировать скелеты и тупикиrmic
компилятор с -poa -iiop
опция. rmic -poa -iiop
команда берет одни или более имен классов в качестве параметра и производит файлы класса формы _MyImpl_Tie.class
и _MyInterface_Stub.class
. Удаленный файл реализации, HelloImpl.class
, имя класса, чтобы передать в этом примере. Для объяснения rmic
опции, обратитесь к Операционной среде Соляриса rmic
страница руководства или Microsoft Windows rmic
страница руководства.
Создать тупик и скелет для HelloImpl
реализация удаленного объекта, выполненная rmic
как это:
rmic -poa -iiop HelloImpl
Предыдущая команда создает следующие файлы:
_HelloInterface_Stub.class
- клиентский тупик_HelloImpl_Tie.class
- скелет сервераЧтобы скомпилировать исходные файлы, работайте javac
команда следующим образом:
javac -d . -classpath . HelloInterface.java HelloServer.java HelloClient.java
Эта команда создает файлы класса HelloInterface.class
, HelloServer.class
, и HelloClient.class
. Они - удаленный интерфейс, сервер, и клиентское приложение соответственно. Для объяснения javac
опции, можно сослаться на Солярис javac
страница руководства или Microsoft Windows javac
страница руководства.
orbd
, который включает и Переходный процесс и Персистентную Службу Именования, и доступен с каждой загрузкой J2SE 1.4 и выше. Для вызывающей стороны (клиент, коллега, или клиентское приложение), чтобы быть в состоянии вызвать метод на удаленный объект, та вызывающая сторона должна сначала получить ссылку на удаленный объект.
Как только удаленный объект регистрируется на сервере, вызывающие стороны могут искать объект по имени, получить ссылку удаленного объекта, и затем удаленно вызвать методы на объект.
Чтобы запустить Службу Именования, работать orbd
из командной строки. Эта команда не производит вывода и обычно выполняется в фоновом режиме. Для больше на orbd
инструмент, можно обратиться к orbd
страница руководства.
Для этого примера, на операционной системе Соляриса:
orbd -ORBInitialPort 1060&
или, на операционной системе Microsoft Windows:
start orbd -ORBInitialPort 1060
Следует определить порт, на котором можно работать orbd
. Для этого примера порт 1060
выбирается, потому что в операционной среде Соляриса, пользователь должен стать корнем, чтобы запустить процесс на порту под 1024.
Следует остановить и перезапустить сервер любое время, Вы изменяете удаленный интерфейс или используете измененные/дополнительные удаленные интерфейсы в реализации удаленного объекта. Иначе, тип ссылки на объект, связанной в Службе Именования, не будет соответствовать измененный класс.
Откройте другое окно терминала и изменитесь на каталог, содержащий исходные файлы для этого примера. Команда для того, чтобы выполнить клиент была распространена ниже, чтобы облегчить читать, но должна быть введена без возвратов между строками. Следующая команда показывает, как запустить HelloServer
сервер. Конечно, если Вы использовали порт кроме 1060 или узел кроме localhost, запускаясь orbd
инструмент, замените те значения в команде ниже с фактическими значениями, используемыми, чтобы запустить orbd
.
java -classpath . -Djava.naming.factory.initial=com.sun.jndi.cosnaming.CNCtxFactory -Djava.naming.provider.url=iiop://localhost:1060 HelloServer
Для объяснения java
опции, можно сослаться на Солярис java
страница руководства или Microsoft Windows java
страница руководства.
Вывод должен быть похожим на это:
Hello Server: Ready ...
orbd
инструмент, замените те значения в команде ниже с фактическими значениями, используемыми, чтобы запустить orbd
. java -classpath . -Djava.naming.factory.initial=com.sun.jndi.cosnaming.CNCtxFactory -Djava.naming.provider.url=iiop://localhost:1060 HelloClientПосле выполнения клиентского приложения Вы будете видеть вывод, подобный следующему в Вашем окне терминала или окне командной строки:
Client: Obtained a ref. to Hello server.
Окно сервера возвратит следующее сообщение:
It works! Hello World!!
Это завершает учебное руководство. Если Вы готовы идти дальше к более сложным приложениям, вот некоторые источники, которые могут помочь: