Опубликован: 10.10.2010 | Уровень: специалист | Доступ: платный
Лекция 9:

CORBA. Третий пример. DII и DSI

< Лекция 8 || Лекция 9: 12 || Лекция 10 >
Аннотация: В лекции приводятся примеры использования механизмов DII и DSI.

Рабочий каталог расположен в Practice.

Приложения, рассматриваемые в предыдущих разделах, строились исходя из предположения о том, что интерфейсы объектов заранее известны. Собственно, иначе и быть не могло, поскольку именно эти интерфейсы и описывались на IDL перед началом разработки приложений.

Однако CORBA позволяет строить приложения, оперирующие объектами, интерфейсы которых неизвестны на момент компиляции приложения. Более того, возможно создание объектов, интерфейс которых будет изменяться в процессе их жизни (под интерфейсом мы понимаем совокупность методов объекта, которые может вызывать клиент). Данные возможности активно применяются при решении задач интеграции приложений, когда CORBA выступает в качестве "клея", связующего компоненты, которые выполнены в различных технологиях.

Соответствующие элементы технологии CORBA носят названия Dynamic Invocation Interface (DII) и Dynamic Skeleton Interface (DSI).

С помощью первой технологии ( DII ) клиенты могут формировать динамические вызовы методов объектов - формировать не в момент компиляции, а в процессе работы.

С помощью второй технологии ( DSI ) серверные объекты могут регистрировать в системе новые методы, которые они будут реализовать, или изменять спецификацию старых. Для написания объектов с использованием этих технологий IDL уже не применяется, и многие из задач, которые раньше решались автоматически сгенерированным кодом, при таком подходе придется решать самостоятельно.

В качестве примера, на котором будет проиллюстрировано использование этих технологий, возьмем уже использованный ранее "Первый пример" из данного раздела. Перепишем клиентский класс таким образом, чтобы он формировал динамические вызовы к серверу (т.е. не использовал клиентскую заглушку), а серверный - так, чтобы он сам регистрировал реализуемые им методы в системе (т.е. не использовал автоматически сгенерированный скелетон).

Сами сигнатуры методов серверного объекта оставим без изменений. Соответственно, для реализации этого примера IDL -файл с описанием интерфейсов не нужен.

Класс BillingServiceImpl

Прежде всего, следует отметить, что поскольку теперь невозможно использовать автоматически сгенерированные классы (их попросту нет), серверный класс должен наследовать от DynamicImplementation и перекрывать его метод invoke,который вызывается при любом обращении клиента.

Диспетчеризацию сообщений теперь придется выполнять вручную, соответствующий код реализован в методе invoke.

Итак, серверный класс будет содержать огромный метод invoke,в котором будет определяться то, какой метод сервера хочет вызвать клиент, и будут извлекаться параметры, переданные клиентом. Соответствующие методы, реализующие операции с картами и изменяющие баланс, полностью аналогичны рассмотренным ранее в предыдущем примере.

1  package com.asw.corba.ex3;
2  
3  import java.util.*;
4  import org.omg.CORBA.*;
5  
6  class BillingServiceImpl extends DynamicImplementation {
7  
8    static String[] myIDs = { "IDL:JavaIDL/DSIBillingService:1.0" };
9  
10    ORB orb;
11  
12    Hashtable hash;
13  
14    BillingServiceImpl(ORB orb) {
15      this.orb = orb;
16      hash = new Hashtable();
17    }
18  
19    public void invoke(ServerRequest request) {
20      try {
21        System.out.println("DSI: invoke called, op = " + request.op_name());
22        if (request.op_name().equals("addNewCard") == true) {
23          /*String personName, String card*/
24          NVList nvlist = orb.create_list(0);
25          Any any1 = orb.create_any();
26          any1.insert_string("");
27          nvlist.add_value("arg1", any1, ARG_IN.value);
28          Any any2 = orb.create_any();
29          any2.insert_string("");
30          nvlist.add_value("arg2", any2, ARG_IN.value);
31          // pass the NVList to the request to get values
32          request.params(nvlist);
33  addNewCard(nvlist.item(0).value().extract_string(), nvlist.item(1).value().extract_string());
34          TypeCode result_tc = orb.get_primitive_tc(TCKind.tk_void);
35          Any result_any = orb.create_any();
36          result_any.type(result_tc);
37          request.result(result_any);
38        } else if (request.op_name().equals("addMoney") == true) {
39          /*String card, double money*/
40          NVList nvlist = orb.create_list(0);
41          Any any1 = orb.create_any();
42          any1.insert_string("");
43          nvlist.add_value("arg1", any1, ARG_IN.value);
44          Any any2 = orb.create_any();
45          any2.insert_double(0);
46          nvlist.add_value("arg2", any2, ARG_IN.value);
47          // pass the NVList to the request to get values
48          request.params(nvlist);
49  addMoney(nvlist.item(0).value().extract_string(), nvlist.item(1).value().extract_double());
50          TypeCode result_tc = orb.get_primitive_tc(TCKind.tk_void);
51          Any result_any = orb.create_any();
52          result_any.type(result_tc);
53          request.result(result_any);
54        } else if (request.op_name().equals("subMoney") == true) {
55          /*String card, double money*/
56          NVList nvlist = orb.create_list(0);
57          Any any1 = orb.create_any();
58          any1.insert_string("");
59          nvlist.add_value("arg1", any1, ARG_IN.value);
60          Any any2 = orb.create_any();
61          any2.insert_double(0);
62          nvlist.add_value("arg2", any2, ARG_IN.value);
63          // pass the NVList to the request to get values
64          request.params(nvlist);
65  subMoney(nvlist.item(0).value().extract_string(), nvlist.item(1).value().extract_double());
66          TypeCode result_tc = orb.get_primitive_tc(TCKind.tk_void);
67          Any result_any = orb.create_any();
68          result_any.type(result_tc);
69          request.result(result_any);
70        } else if (request.op_name().equals("getCardBalance") == true) {
71          /*String card, double money*/
72          NVList nvlist = orb.create_list(0);
73          Any any1 = orb.create_any();
74          any1.insert_string("");
75          nvlist.add_value("arg1", any1, ARG_IN.value);
76          // pass the NVList to the request to get values
77          request.params(nvlist);
78  double d = getCardBalance(nvlist.item(0).value().extract_string());
79  TypeCode result_tc = orb.get_primitive_tc(TCKind.tk_double);
80          Any result_any = orb.create_any();
81          result_any.insert_double(d);
82          request.result(result_any);
83        }
84      } catch (Exception ex) {
85        ex.printStackTrace();
86        System.out.println("DSIExample: Exception thrown: " + ex);
87      }
88    }
89  
90    // implement an _ids method to return repository ID of interface
91    public String[] _ids() {
92      return myIDs;
93    }
94  
95    public void addNewCard(String personName, String card) {
96      hash.put(card, new Double(0.0));
97    }
98  
99    public void addMoney(String card, double money) {
100      synchronized (hash) {
101        Double d = (Double) hash.get(card);
102        if (d != null)
103          hash.put(card, new Double(d.doubleValue() + money));
104      }
105    }
106  
107    public void subMoney(String card, double money) {
108      Double d = (Double) hash.get(card);
109  
110      if (d != null)
111        hash.put(card, new Double(d.doubleValue() - money));
112    }
113  
114    public double getCardBalance(String card) {
115      Double d = (Double) hash.get(card);
116      if (d != null)
117        return d.doubleValue();
118      else
119        return 0;
120    }
121  }
Листинг 9.1. Класс BillingServiceImpl

Итак, метод invoke вызывается брокером запросов при вызове любого метода объекта, и его единственным параметром является ServerRequest - объект, содержащий всю необходимую информацию о вызове: имя вызываемого метода, список параметров и их типы. Поэтому в первую очередь проверяется имя вызываемого метода - оно может быть получено с помощью вызова op_name(),примененного к переданному ServerRequest.Далее, поскольку методы, как правило, принимают и возвращают аргументы, необходимо, во-первых, извлечь аргументы, переданные клиентом, а во-вторых, возвратить клиенту результат, если это необходимо.

Для извлечения из ServerRequest значений переданных клиентом аргументов необходимо выполнить следующие действия.

Создать список, в который затем будут считаны значения аргументов:

NVList nvlist = orb.create_list(0);

Заполнить список объектами, в которые будут считаны значения переданных клиентом аргументов. В данном случае список заполняется двумя объектами типа Any (это специальный тип CORBA, совместимый со всеми типами), которым присваиваются некоторые начальные значения (пустые строки) и которые заносятся в список аргументов как принимаемые аргументы (направление передачи параметров - in).

Any any1 = orb.create_any(); 
any1.insert_string("");
nvlist.add_value("arg1", any1, ARG_IN.value); 
Any any2 = orb.create_any(); 
any2.insert_double(0);
nvlist.add_value("arg2", any2, ARG_IN.value);

Затем подготовленный список аргументов передается в ServerRequest и с помощью вызова request.params(nvlist) заполняется значениями, переданными клиентом.

Для того чтобы получить доступ к этим значениям, можно воспользоваться методом extract_<datatype> (например, для получения значения первого переданного аргумента, при условии, что он является строковым, можно воспользоваться вызовом nvlist.item(0).value().extract_string()).Следует обратить внимание, что для получения значения аргумента необходимо явно указывать его тип, вызывая соответствующий метод семейства extract*.

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

TypeCode result_tc = orb.get_primitive_tc(TCKind.tk_double); 
Any result_any = orb.create_any(); 
result_any.insert_double(d); 
request.result(result_any);

Сначала формируется TypeCode соответствующего типа (в данном случае предполагается, что метод возвращает результат типа double).Затем создается объект для результата (типа Any).Затем в этот объект помещается результат (с помощью одного из методов семейства insert*),после чего объект помещается в ServerRequest для возврата клиенту.

Следует обратить внимание, что даже если метод никакого результата не возвращает (имеет тип возврата void),возврат все равно должен быть сформирован, только в качестве его типа должно быть указано TCKind.tk_void.

< Лекция 8 || Лекция 9: 12 || Лекция 10 >
Алмаз Мурзабеков
Алмаз Мурзабеков
Прохожу курс "Построение распределенных систем на Java" в третьей лекции где описывается TCPServer вылетает эта ошибка
"Connection cannot be resolved to a type"


Java version 1.7.0_05
Александр Хвостов
Александр Хвостов
Россия
Максим Лютов
Максим Лютов
Россия, СПб, Политех, 2012