Реализация почтового клиента и сервера на основе CORBA
11
Факультет «Информатика и системы управления»
Методические указания к лабораторной работе
по курсу «Распределенные системы обработки информации»
"Реализация почтового клиента и сервера на основе CORBA"
Москва, 2004 г.
Цель работы
1. Познакомиться с технологией CORBA.
2. Познакомиться с языком IDL и описанием интерфейсов.
3. Освоить классы библиотеки org.omg.
4. Применить полученные знания на практике
1. Задание для домашней подготовкиОзнакомиться с теоретическим материалом, представленным в приложениях к данным методическим указаниям и примерами программ. Ознакомиться с текстом задания к лабораторной работе, предложить размещение компонентов и функциональность, удовлетворяющую требованиям задания к лабораторной работе, и написать программу.
2. Задание к лабораторной работеРазработать почтовый клиент и сервер. Клиент - оконное приложение, которое будет позволять отсылать и получать с сервера сообщения. Идентификация клиентов на сервере, протокол передачи сообщений - на усмотрение студентов.Сервер может быть консольным приложением. Хранить сообщения можно в текстовом файле. Рекомендуется сделать сервер многопоточным.Для взаимодействия клиента и сервера использовать технологию CORBA.В качестве дополнения предлагается сервер или клиент реализовать не на Java.
3. Содержание отчетаОтчет должен содержать:
Постановку задачи, решаемой отлаженной программой.
Руководство пользователя отлаженной программы, содержащее описание интерфейсов всех функций программы.
Листинг программы с необходимыми комментариями.
4. Контрольные вопросы1. Что такое CORBA?
2. Что такое IDL? Для чего он нужен?
3. Как осуществляется взаимодействие клиента и сервера в CORBA?
4. Как передаются данные между ними?
5. Для чего нужен сервер имен?
6. Как запускается CORBA_сервер?
5. Литература1. Кен Арнольд, Джеймс Гослинг, Дэвид Холмс. Язык программирования Java™.
2. Официальный сайт Java - http://java.sun.com/ (есть раздел на русском языке с учебником).
3. Java™ 2 SDK, Standard Edition Documentation - http://java.sun.com/products/jdk/1.5/index.html.
4. Джеймс Гослинг, Билл Джой, Гай Стил. Спецификация языка Java (The Java Language Specification - http://www.javasoft.com/docs/books/jls/). Перевод на русский язык - http://www.uni-vologda.ac.ru/java/jls/index.html
5. Официальный сайт проекта Eclipse - http://www.eclipse.org/.
6.
Приложение 1. CORBAТехнология CORBA (Common Object Request Broker Architecture) - это стандарт написания распределенных приложений, предложенный консорциумом OMG (Open Management Group). Создавая CORBA_объекты, мы можем, например, существенно уменьшить время решения задач, требующих выполнения большого объема вычислений. Это возможно благодаря размещению CORBA_объектов на разных машинах. Каждый удаленный объект решает определенную подзадачу, тем самым разгружает клиент от выполнения лишней работы.Основу CORBA составляет объектный брокер запросов (Object Request Broker). ORB управляет взаимодействием объектов в распределенной сетевой среде. IIOP (Internet Inter-ORB Protocol) - это специальный протокол взаимодействия между ORB.В адресном пространстве клиента функционирует специальный объект, называемый заглушкой (stub). Поучив запрос от клиента, он упаковывает параметры запроса в специальный формат и передает его серверу, а точнее скелету.Скелет (skeleton) - объект, работающий в адресном пространстве сервера. Получив запрос от клиента, он распаковывает его и передает серверу. Также скелет преобразует ответы сервера и передает их клиенту (заглушке).Для того чтобы написать любое приложение CORBA используя технологию Java, необходимо иметь две вещи - это установленный пакет JDK1.5 и компилятор idlj (…\jdk1.5.0\bin\idlj.exe). JDK предоставляет набор классов для работы с CORBA объектами, а idlj производит отображение языка IDL в Java.6
.1 Создание простейшего CORBA-приложения6.1.1 Написание интерфейсаСоздание CORBA приложения на Java начинается с написания интерфейса для удаленного объекта, используя язык описания интерфейсов (Interface Definition Language, IDL).
Создадим файл hello.idl
module HelloApp
{
interface Hello
{
string sayHello();
oneway void shutdown();
};
};
Данный интерфейс описывает лишь два метода shutdown и sayHello. Причем, нам не важно, что делают эти методы, главное мы определяем, что они есть и определяем какие у них входные и выходные параметры.
Далее следует запустить компилятор IDL-to-Java idlj:
idlj - fall Hello.idl
В текущей директории появилась новая папка HelloApp, в которой содержаться шесть java_файлов. Каждый из них имеет свое назначение.
· HelloPOA.java java - абстрактный класс, который представляет собой ни что иное, как скелет сервера (skeleton) и обеспечивает функциональность сервера.
· _HelloStub.java - класс, реализующий заглушку (stub) клиента. Обеспечивает функциональность клиента.
· HelloHelper.java и HelloHolder.java - классы, предоставляющие вспомогательные функции для CORBA объектов.
· HelloOperations.java - класс, содержащий описание интерфейса hello на языке Java.
· Hello.java - класс - наследник HelloOperations, поддерживающий интерфейс org.omg.CORBA. Object.
6.1.2 Создание сервераТеперь наша задача - написать класс, реализующий интерфейс
hello. В нашем случае это будет
HelloImpl. Обратите внимание, на то, что он является наследником класса
HelloPOA. В
HelloImpl реализованы методы, объявленные в
Hello.idl.
Для упрощения задачи объявление методов можно взять из файла HelloOperations.java, сгенерированного jdlj.class HelloImpl extends HelloPOA {
private ORB orb;
public void setORB (ORB orb_val) {
orb = orb_val;
}
// implement sayHello() method
public String sayHello() {
return «\nHello world!!\n»;
}
// implement shutdown() method
public void shutdown() {
orb.shutdown(false);
}
}
Следующим шагом будет создание собственно серверной части приложения. Это будет класс HelloServer.
В нем будет всего один метод - стандартная функция main.
Первое что мы делаем, создаем ORB. Затем создаем экземпляр класса удаленного объекта (HelloImpl) и регистрируем его в ORB. Дальше вызываем специальную службу имен (NameService) и регистрируем в ней имя удаленного объекта, чтобы клиент смог его найти.
Рассмотрим подробнее эти этапы.
1. Создание и инициализация ORB. Производится вызовом статического метода init класса ORB
ORB orb = ORB.init (args, null);
2. Создание экземпляра класса удаленного объекта и регистрация его в ORB
HelloImpl helloImpl = new HelloImpl();
helloImpl.setORB(orb);
3. Получение контекста имен (NamingContext)
org.omg.CORBA. Object objRef = orb.resolve_initial_references («NameService»);
NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);
В первой строчке мы получаем объектую ссылку на службу имен (NameService). Но фактически это обыкновенный CORBA_объект и для того, чтобы использовать его как контекст имен (NamingContext), необходимо вызвать метод narrow класса NamingContextHelper, который как бы конкретизирует данный CORBA_объект.
4. Регистрация имени удаленного объекта (HelloImpl)
String name = «Hello»;
NameComponent path[] = ncRef.to_name(name);
ncRef.rebind (path, href);
Регистрация имени производится для того, чтобы клиент смог найти удаленный объект. Этой цели служит функция rebind (NameComponent[] nc, Object obj) интерфейса NamingContext.
5. Ожидание запросов от клиента
orb.run();
Теперь сервер готов к работе.
// HelloServer.java
import HelloApp.*;
import org.omg. CosNaming.*;
import org.omg. CosNaming. NamingContextPackage.*;
import org.omg.CORBA.*;
import org.omg. PortableServer.*;
import org.omg. PortableServer.POA;
import java.util. Properties;
class HelloImpl extends HelloPOA {
private ORB orb;
public void setORB (ORB orb_val) {
orb = orb_val;
}
// implement sayHello() method
public String sayHello() {
return «\nHello world!!\n»;
}
// implement shutdown() method
public void shutdown() {
orb.shutdown(false);
}
}
public class HelloServer {
public static void main (String args[]) {
try {
// create and initialize the ORB
ORB orb = ORB.init (args, null);
// get reference to rootpoa & activate the POAManager
POA rootpoa = POAHelper.narrow (orb.resolve_initial_references («RootPOA»));
rootpoa.the_POAManager().activate();
// create servant and register it with the ORB
HelloImpl helloImpl = new HelloImpl();
helloImpl.setORB(orb);
// get object reference from the servant
org.omg.CORBA. Object ref = rootpoa.servant_to_reference(helloImpl);
Hello href = HelloHelper.narrow(ref);
// get the root naming context
// NameService invokes the name service
org.omg.CORBA. Object objRef =
orb.resolve_initial_references («NameService»);
// Use NamingContextExt which is part of the Interoperable
// Naming Service (INS) specification.
NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);
// bind the Object Reference in Naming
String name = «Hello»;
NameComponent path[] = ncRef.to_name(name);
ncRef.rebind (path, href);
System.out.println («HelloServer ready and waiting…»);
// wait for invocations from clients
orb.run();
}
catch (Exception e) {
System.err.println («ERROR:» + e);
e.printStackTrace (System.out);
}
System.out.println («HelloServer Exiting…»);
}
}
6.1.3 Создание клиентаПерейдем к написанию кода для клиента.Основные шаги написания клиентского приложения1. Создание и инициализация ORB2. Получение контекста службы имен (
NamingContext)3. Нахождение удаленного объекта4. Вызов метода
sayHello.5. Вызов метода
shutdown.Как видно, первые два пункта совпадают с этапами создания серверного приложения, поэтому рассматривать их не будем.Третий пункт реализуется тоже достаточно просто. Создается объект NameComponent. Вызывается метод resolve (NameComponent[] path), который отыскивает по имени удаленный объект (стандартный CORBA_объект). При помощи метода
narrow (org.omg.CORBA. Object obj) класса
helloHelper (сгенерированного
idlj компилятором) получаем объектную ссылку на интерфейс
hello.String name = «Hello»;helloImpl = HelloHelper.narrow (ncRef.resolve_str(name));Теперь можно вызывать метод
sayHello:System.out.println (helloImpl.sayHello());Метод shutdown завершает работы сервера.helloImpl.shutdown(); //testClient.javaimport HelloApp.*;import org.omg. CosNaming.*;import org.omg. CosNaming. NamingContextPackage.*;import org.omg.CORBA.*;public class HelloClient{static Hello helloImpl;public static void main (String args[]){try { // create and initialize the ORBORB orb = ORB.init (args, null); // get the root naming contextorg.omg.CORBA. Object objRef =orb.resolve_initial_references («NameService»); // Use NamingContextExt instead of NamingContext. This is // part of the Interoperable naming Service.NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef); // resolve the Object Reference in NamingString name = «Hello»;helloImpl = HelloHelper.narrow (ncRef.resolve_str(name));System.out.println («Obtained a handle on server object:» + helloImpl);System.out.println (helloImpl.sayHello());helloImpl.shutdown();} catch (Exception e) {System.out.println («ERROR:» + e);e.printStackTrace (System.out);}}}
6.1.4 Компиляция и запуск приложенияФайлы HelloServer.java and HelloClient.java, Hello.idl и папка HelloApp, созданная idkj.exe должны храниться в одной папке.Для компиляции клиента и сервера надо в командной строке набратьjavac *.java HelloApp/*.javajavac.exe находится в …\jdk1.5.0\bin.Среда Eclipse не позволяет запускать CORBA_приложения. Для запуска1. Запустить службу orbd - Object Request Broker Daemon (…\jdk1.5.0\bin\orbd.exe). Это делается, чтобы мы смогли получить ссылку на службу имен.start orbd - ORBInitialPort 1050Параметр - ORBInitialPort - номер порта, на котором будет работать сервер имен.2. Запуск сервераstart java HelloServer - ORBInitialPort 1050 - ORBInitialHost localhostУказывается порт, на котором работает сервер имен. Параметр - ORBInitialHost указывает хост, на котором работает сервер имен.3. Запуск клиентаjava HelloClient - ORBInitialPort 1050 - ORBInitialHost localhostУказывается порт, на котором работает сервер имен. Параметр - ORBInitialHost указывает хост, на котором работает сервер имен.Для удобства компиляции и запуска можно создать bat_файл:idlj - fall Hello.idljavac *.java HelloApp/*.javastart java HelloServer - ORBInitialPort 1050 - ORBInitialHost localhostjava HelloClient - ORBInitialPort 1050 - ORBInitialHost localhost
6.2 Язык IDLЯзык OMG IDL (Interface Definition Language - Язык Описания Интерфейсов) представляет собой технологически независимый синтаксис для описания интерфейсов объектов. При описании программных архитектур, OMG IDL прекрасно используется в качестве универсальной нотации для определения границ объекта, определяющих его поведение по отношению к другим компонентам информационной системы. OMG IDL позволяет описывать интерфейсы, имеющие различные методы и атрибуты. Язык также поддерживает наследование интерфейсов, что необходимо для повторного использования объектов с возможностью их расширения или конкретизации.IDL является чисто декларативным языком, то есть он не содержит никакой реализации. IDL_спецификации могут быть откомпилированы (отображены) в заголовочные файлы и специальные прототипы серверов, которые могут использоваться непосредственно программистом. То есть IDL_определенные методы могут быть написаны, а затем выполнены, на любом языке, для которого существует отображение из IDL. К таким языкам относятся C, C++, SmallTalk, Pascal, Java, Ada.С помощью IDL можно описать и атрибуты компоненты, и родительские классы которые, она наследует, и вызываемые исключения, и, наконец, методы, определяющие интерфейс, причем с описанием входных и выходных параметров.Структура CORBA IDL файла выглядит следующим образом:
module <identifier> {
<type declarations>;
<constant declarations>;
<exception declarations>;
interface <identifier> [:<inheritance>] {
<type declarations>;
<constant declarations>;
<attribute declarations>;
<exception declarations>;
[<op_type>]<identifier>(<parameters>)
[raises exception] [context]
.
.
[<op_type>]<identifier>(<parameters>)
[raises exception] [context]
.
.
}
interface <identifier> [:<inheritance>]
.
.
}
Синтаксис языка IDL довольно объемный и не представляется возможным описать его в методическом пособии.
Для реализации интерфейса почтового сервера можно дополнить Hello.idl
module HelloApp
{
struct TMessage
{
string To;
string From;
string Message;
};
typedef sequence<TMessage> TMessages;
interface Hello
{
TMessages GetMessages (in string Name, out short count);
oneway void Send (in string Client, in string Name, in string Message);
string sayHello();
oneway void shutdown();
};
};
typedef sequence<TMessage> TMessages; - объявление типа динамический массив сообщений TMessage.