On-Line Библиотека www.XServer.ru - учебники, книги, статьи, документация, нормативная литература.
       Главная         В избранное         Контакты        Карта сайта   
    Навигация XServer.ru




Загрузка...




 

Простое CORBA приложение - своими руками

Александр Годин

Технология CORBA - это стандарт написания распределенных приложений, предложенный консорциумом OMG (Open Management Group). Создавая CORBA-объекты, мы можем ,например, существенно уменьшить время решения задач, требующих выполнения большого объема вычислений. Это возможно благодаря размещению CORBA-объектов на разных машинах. Каждый удаленный объект решает определенную подзадачу, тем самым разгружает клиент от выполнения лишней работы.

Рассмотрим взаимодействие объектов в архитектуре CORBA

Рис.1 Взаимодействие объектов в архитектуре CORBA

Основу CORBA составляет объектный брокер запросов (Object Request Broker). ORB управляет взаимодействием объектов в распределенной сетевой среде. IIOP (Internet Inter-ORB Protocol) - это специальный протокол взаимодействия между ORB.

В адресном пространстве клиента функционирует специальный объект, называемый заглушкой (stub). Поучив запрос от клиента, он упаковывает параметры запроса в специальный формат и передает его серверу, а точнее скелету.

Скелет (skeleton) - объект, работающий в адресном пространстве сервера. Получив запрос от клиента, он распаковывает его и передает серверу. Также скелет преобразует ответы сервера и передает их клиенту (заглушке).

Для того, чтобы написать любое приложение CORBA используя технологию Java, необходимо иметь две вещи - это установленный пакет JDK1.2 и компилятор idltojava. JDK предоставляет набор классов для работы с CORBA объектами, а idltojava производит отображение языка IDL в Java.

Создание CORBA приложения на Java начинается с написания интерфейса для удаленного объекта, используя язык описания интерфейсов (Interface Definition Language, IDL).

Создадим файл test.idl

module testApp {
    interface test
    {
       long count(in string msg);
    };
};

Данный интерфейс описывает лишь один метод count. Причем, нам не важно, что делает этот метод, главное мы определяем, что он есть, определяем какие у него входные и выходные параметры.

Воспользуемся компилятором idltojava.

	idltojava Hello.idl
Примечание. Данный компилятор по умолчанию использует препроцессор языка С++, поэтому что бы не мучится с сообщением об ошибке имя команды или файла указано неправильно (в переменной окружения CPP должен быть прописан путь к нему) отключим его использование, установив флаги.
	idltojava -fno-cpp Hello.idl
Результат работы данной программы можно представить в виде схемы. 

Рис.2 Работа idltojava компилятора


В текущей директории появилась новая папка testApp, в которой содержатся пять java - файлов. Каждый из них имеет свое назначение.

_testImplBase.java - абстрактный класс, который представляет собой не что иное, как скелет сервера (skeleton) и обеспечивает функциональность сервера;

_testStub.java - класс, реализующий заглушку (stub) клиента. Обеспечивает функциональность клиента;

test.java - класс, содержащий описание интерфейса test на языке Java;

testHelper.java и testHolder.java - классы, предоставляющие вспомогательные функции для CORBA объектов.

Теперь наша задача - написать класс, реализующий интерфейс test. Такие классы должны называться так, чтобы в их имени было слово 'Servant', в нашем случае это будет testServant.

class testServant extends _testImplBase
{
    public int count(String msg)
    {
	return msg.length();
    }
}

Обратите внимание, что этот класс унаследован от _testImplBase. Как видно, здесь реализован метод count, который в данном примере считает количество букв в принятом сообщении.

Теперь перейдем непосредственно к написанию серверной части приложения.

Первое что мы делаем, создаем ORB. Затем создаем экземпляр класса удаленного объекта (testServant) и регистрируем его в ORB. Дальше вызываем специальную службу имен (NameService) и регистрируем в ней имя удаленного объекта, чтобы клиент смог его найти (есть и другой способ нахождения удаленного объекта, но о нем чуть позже).

Рассмотрим подробнее эти этапы.

  1. Создание и инициализация ORB. Производится вызовом статического метода init класса ORB

    ORB orb = ORB.init();

  2. Создание экземпляра класса удаленного объекта и регистрация его в ORB

    testServant testRef = new testServant();

    orb.connect(testRef);

  3. Получение контекста имен (NamingContext)

    org.omg.CORBA.Object objRef =

    orb.resolve_initial_references("NameService");

    NamingContext ncRef = NamingContextHelper.narrow(objRef);

    в первой строчке мы получаем объектую ссылку на службу имен (NameService). Но фактически это обыкновенный CORBA-объект и для того, чтобы использовать его как контекст имен (NamingContext), необходимо вызвать метод narrow класса NamingContextHelper, который как бы конкретизирует данный CORBA-объект.

  4. Регистрация имени удаленного объекта (testServant)

    Как было сказано раньше регистрация имени производится для того чтобы клиент смог найти удаленный объект. Этой цели служит функция rebind(NameComponent[] nc, Object obj) интерфейса NamingContext.

        NameComponent nc = new NameComponent("test", "");
         //первый параметр
         //указывает имя объекта,
         //второй нам использовать не обязательно
        NameComponent path[] = {nc};
        ncRef.rebind(path, testRef);
  5. Ожидание запросов от клиента.
    java.lang.Object sync = new java.lang.Object();
               synchronized (sync) {
                    sync.wait();
               }

    После того как сервер обработает запрос от клиента и выполнит метод count он снова перейдет в состояние ожидания.

Теперь сервер готов к работе

Листинг 1. testServer.java

import testApp.*;
import org.omg.CosNaming.*;
import org.omg.CosNaming.NamingContextPackage.*;
import org.omg.CORBA.*;
import java.lang.*;

class testServant extends _testImplBase
{
    public int count(String msg)
    {
return msg.length();
    }
}

public class testServer {

    public static void main(String args[])
    {
	try
	{
    	ORB orb = ORB.init(args, null);

    	testServant testRef = new testServant();
    	orb.connect(testRef);

    	org.omg.CORBA.Object objRef =
         orb.resolve_initial_references("NameService");
    	NamingContext ncRef =
    	 NamingContextHelper.narrow(objRef);

 	NameComponent nc = new NameComponent("test", "");
    	NameComponent path[] = {nc};
    	ncRef.rebind(path, testRef);

    	java.lang.Object sync = new java.lang.Object();
    	synchronized (sync) {
        sync.wait()
	}

	}
	catch (Exception e) {
    	System.err.println("ERROR: " + e);
    	e.printStackTrace(System.out);
	}
    }
}

Обратите внимание на то, что все операции выполняемые над CORBA-объектами заключены в try-catch блок.

Перейдем к написанию кода для клиента.

Основные шаги написания клиентского приложения

  1. Создание и инициализация ORB
  2. Получение контекста службы имен (NamingContext)
  3. Нахождение удаленного объекта
  4. Вызов метода count.

Как видно, первые два пункта совпадают с этапами создания серверного приложения, поэтому рассматривать их не будем.

Третий пункт реализуется тоже достаточно просто. Создается объект NameComponent. Вызывается метод resolve(NameComponent[] path), который отыскивает по имени удаленный объект (стандартный CORBA-объект). При помощи метода narrow(org.omg.CORBA.Object obj) класса testHelper (сгенерированного idltojava компилятором) получаем объектную ссылку на интерфейс test.

	NameComponent nc = new NameComponent("test", "");
	NameComponent path[] = {nc};
	org.omg.CORBA.Object obj= ncRef.resolve(path);
	test testRef = testHelper.narrow(obj);

Теперь можно вызывать метод count

	String msg = "try to count";
	int count = testRef.count(msg);

Листинг 2. testClient.java

import testApp.*;
import org.omg.CosNaming.*;
import org.omg.CORBA.*;
import java.lang.*;

public class testClient
{
    public static void main(String args[])
    {
	try
	{
	  ORB orb = ORB.init(args, null);
	  org.omg.CORBA.Object objRef =
           orb.resolve_initial_references("NameService");

	  NamingContext ncRef =
	       NamingContextHelper.narrow(objRef);
	  NameComponent nc = new NameComponent("test", "");
	  NameComponent path[] = {nc};
	  test testRef =
	       testHelper.narrow(ncRef.resolve(path));

	  String msg = "try to count";
	  int count = testRef.count(msg);
	  System.out.println
	      ('number of chars in message is:' + count);

	}
	catch (Exception e)
	{
	  System.out.println("ERROR : " + e) ;
	  e.printStackTrace(System.out);
	}
	}
}

Запуск приложения

  1. Запуск сервера имен (входит в поставку с JDK1.2). Это делается, чтобы мы смогли получить ссылку на службу имен
        tnameserv 

    по умолчанию сервер запускается по порту 900. Это значение можно изменить, указав параметр запуска -ORBInitialPort, например

        tnameserv -ORBInitialPort 1024
  2. Запуск сервера testServer
        java testServer -ORBInitialPort 1024
             // указывается тот порт
             //по которому работает сервер имен
  3. Запуск клиента testClient
    java testClient
            -ORBInitialHost javas.stu.neva.ru
            -ORBInitialPort 1024

    параметр -ORBInitialHost указывает хост на котором работает testServer

после выполнения этого приложения, на консоль будет выведено

 number of chars in message is:12

Соединение с сервером без использования службы имен

Основная идея этого метода состоит в том, что сервер сохраняет экземпляр класса удаленного объекта (testServant) в виде текстового файла в любом месте, доступном клиенту. Клиент загружает из файла данные (в объект String) и преобразует специальными методами в объектную ссылку на удаленный объект.

Все это реализуется следующим образом

Удалим некоторую часть кода - это касается и клиента (testServer.java и testClient.java)

  1. Исключим из import библиотеки
    	org.omg.CosNaming.*;
    	org.omg.CosNaming.NamingContextPackage.*;
  2. Удалим код соответствующий п.3-п.4
Вместо удаленного кода вставим - для сервера:
   //преобразуем объект в строку
   String ior = orb.object_to_string(testRef);
   String filename = System.getProperty("user.home") +
   System.getProperty("file.separator")+"test_file";

   //создаем файл test_file
   FileOutputStream fos = new FileOutputStream(filename);
   PrintStream ps = new PrintStream(fos);
   //записываем в него данные
   ps.print(ior);
   ps.close();

для клиента:

   String filename = System.getProperty("user.home") +
   System.getProperty("file.separator")+"test_file";
   //открываем файл
   FileInputStream fis = new FileInputStream(filename);
   DataInputStream dis = new DataInputStream(fis);
   //читаем данные
   String ior = dis.readLine();
   //преобразуем в объект CORBA
   org.omg.CORBA.Object obj = orb.string_to_object(ior);
   //получаем ссылку на удаленный объект
   test testRef = testHelper.narrow(obj);

Скомпилируем приложения, запустим сервер и клиент аналогично тому, как мы делали это раньше (сервер имен запускать в данном случае не надо).



Языки программирования: разное