Рабочий каталог расположен в
Приложения, рассматриваемые в предыдущих разделах, строились исходя из предположения о том, что IDL перед началом разработки приложений.
Однако CORBA позволяет строить приложения, оперирующие объектами, интерфейсы которых неизвестны на момент компиляции приложения. Более того, возможно создание объектов, интерфейс которых будет изменяться в процессе их жизни (под интерфейсом мы понимаем совокупность методов объекта, которые может вызывать клиент). Данные возможности активно применяются при решении задач CORBA выступает в качестве "клея", связующего компоненты, которые выполнены в различных технологиях.
Соответствующие элементы технологии CORBA носят названия Dynamic Invocation Interface (DII) и Dynamic Skeleton Interface (DSI).
С помощью первой технологии ( DII ) клиенты могут формировать динамические вызовы методов объектов - формировать не в момент компиляции, а в процессе работы.
С помощью второй технологии ( ) серверные объекты могут регистрировать в системе новые методы, которые они будут реализовать, или изменять спецификацию старых. Для написания объектов с использованием этих технологий 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 }
Итак, метод invoke вызывается брокером запросов при вызове любого метода объекта, и его единственным параметром является ServerRequest - объект, содержащий всю необходимую информацию о вызове: имя вызываемого метода, список параметров и их типы. Поэтому в первую очередь проверяется имя вызываемого метода - оно может быть получено с помощью вызова op_name(),примененного к переданному ServerRequest.Далее, поскольку методы, как правило, принимают и возвращают аргументы, необходимо, во-первых, извлечь аргументы, переданные клиентом, а во-вторых, возвратить клиенту результат, если это необходимо.
Для извлечения из ServerRequest значений переданных клиентом аргументов необходимо выполнить следующие действия.
Создать список, в который затем будут считаны значения аргументов:
NVList nvlist = orb.create_list(0);
Заполнить список объектами, в которые будут считаны значения переданных клиентом аргументов. В данном случае список заполняется двумя объектами типа Any (это специальный тип CORBA, совместимый со всеми типами), которым присваиваются некоторые начальные значения (пустые строки) и которые заносятся в
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.
Класс BillingServiceServer
Класс BillingServiceServer служит для создания экземпляра BillingServiceImpl и его регистрации в сервисе имен. Он ничем не отличается от подобных классов, рассмотренных нами ранее.
1 package com.asw.corba.ex3;
2
3 import org.omg.CosNaming.*;
4 import org.omg.CORBA.*;
5
6 public class BillingServiceServer {
7
8 public static void main(String args[]) {
9 try {
10 // create and initialize the ORB
11 ORB orb = ORB.init(args, null);
12 // create servant and register it with the ORB
13 BillingServiceImpl BSRef = new BillingServiceImpl(orb);
14 orb.connect(BSRef);
15 System.out.println(BSRef);
16 org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService");
17 NamingContext ncRef = NamingContextHelper.narrow(objRef);
18 // bind the Object Reference in Naming
19 NameComponent nc = new NameComponent("BillingService", "");
20 NameComponent path[] = { nc };
21 ncRef.rebind(path, BSRef);
22 java.lang.Object sync = new java.lang.Object();
23 synchronized (sync) { sync.wait(); }
24 } catch (Exception e) {
25 System.err.println("ERROR: " + e);
26 e.printStackTrace(System.out);
27 }
28 }
29 }
Класс BillingServiceClient
Клиентский класс, так же как и серверный, не использует сгенерированные вспомогательные классы. Это означает, что необходимо вручную сформировать все вызовы к серверу, т.е. определить вызываемый метод, сформировать список передаваемых аргументов, осуществить вызов и получить результат.
1 package com.asw.corba.ex3;
2
3 import org.omg.CosNaming.*;
4 import org.omg.CORBA.*;
5
6 public class BillingServiceClient {
7 org.omg.CORBA.Object BSImpl;
8
9 ORB orb;
10
11 void testAddNewCard(String personName, String card) {
12 org.omg.CORBA.Request r2 = BSImpl._request("addNewCard");
13 r2.set_return_type(orb.get_primitive_tc(org.omg.CORBA.TCKind.tk_void));
14 org.omg.CORBA.Any inc = r2.add_in_arg();
15 inc.insert_string(personName);
16 org.omg.CORBA.Any inc2 = r2.add_in_arg();
17 inc2.insert_string(card);
18 r2.invoke();
19 java.lang.Exception ex = r2.env().exception();
20 if (ex instanceof org.omg.CORBA.UnknownUserException) {
21 org.omg.CORBA.UnknownUserException userEx = (org.omg.CORBA.UnknownUserException) ex;
22 }
23 }
24
25 void testAddMoney(String card, double amount) {
26 org.omg.CORBA.Request r2 = BSImpl._request("addMoney");
27 r2.set_return_type(orb.get_primitive_tc(org.omg.CORBA.TCKind.tk_void));
28 org.omg.CORBA.Any inc = r2.add_in_arg();
29 inc.insert_string(card);
30 org.omg.CORBA.Any inc2 = r2.add_in_arg();
31 inc2.insert_double(amount);
32 r2.invoke();
33 java.lang.Exception ex = r2.env().exception();
34 if (ex instanceof org.omg.CORBA.UnknownUserException) {
35 org.omg.CORBA.UnknownUserException userEx = (org.omg.CORBA.UnknownUserException) ex;
36 }
37 String result;
38 }
39
40 void testSubMoney(String card, double amount) {
41 org.omg.CORBA.Request r2 = BSImpl._request("subMoney");
42 r2.set_return_type(orb.get_primitive_tc(org.omg.CORBA.TCKind.tk_void));
43 org.omg.CORBA.Any inc = r2.add_in_arg();
44 inc.insert_string(card);
45 org.omg.CORBA.Any inc2 = r2.add_in_arg();
46 inc2.insert_double(amount);
47 r2.invoke();
48 java.lang.Exception ex = r2.env().exception();
49 if (ex instanceof org.omg.CORBA.UnknownUserException) {
50 org.omg.CORBA.UnknownUserException userEx = (org.omg.CORBA.UnknownUserException) ex;
51 }
52 String result;
53 }
54
55 double testGetCardBalance(String card) {
56 org.omg.CORBA.Request r2 = BSImpl._request("getCardBalance");
57 r2.set_return_type(orb.get_primitive_tc (org.omg.CORBA.TCKind.tk_double));
58 org.omg.CORBA.Any inc = r2.add_in_arg();
59 inc.insert_string(card);
60 r2.invoke();
61 java.lang.Exception ex = r2.env().exception();
62 if (ex instanceof org.omg.CORBA.UnknownUserException) {
63 org.omg.CORBA.UnknownUserException userEx = (org.omg.CORBA.UnknownUserException) ex;
64 }
65 double result;
66 result = r2.return_value().extract_double();
67 System.out.println("Balance= " + result);
68 return result;
69 }
70
71 public void doTest(String args[]) throws Exception {
72 orb = ORB.init(args, null);
73 org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService");
74 NamingContext ncRef = NamingContextHelper.narrow(objRef);
75 // resolve the Object Reference in Naming
76 NameComponent nc = new NameComponent("BillingService", "");
77 NameComponent path[] = { nc };
78 BSImpl = ncRef.resolve(path);
79 System.out.println(BSImpl);
80 this.testAddNewCard("Ivan", "1");
81 this.testAddMoney("1", 10.2);
82 this.testGetCardBalance("1");
83 this.testSubMoney("1", 8.1);
84 this.testGetCardBalance("1");
85 }
86
87 public static void main(String args[]) {
88 try {
89 BillingServiceClient bsc = new BillingServiceClient();
90 bsc.doTest(args);
91 } catch (Exception e) {
92 System.out.println("ERROR : " + e);
93 e.printStackTrace(System.out);
94 }
95 }
96 }
Формирование динамического вызова метода сервера осуществляется следующим образом.
У полученной у сервиса имен объектной ссылки (она имеет тип org.omg.CORBA.Object) вызовом метода request (в качестве аргумента этому методу передается имя вызываемого метода сервера) получаем org.omg.CORBA.Request - объект, который используется для осуществления запросов к серверу.
Первое, что необходимо указать, - тип возвращаемого методом значения:
r2.set_return_type(orb.get_primitive_tc (org.omg.CORBA.TCKind.tk_double));
Затем необходимо поместить в запрос передаваемые аргументы:
Заorg.omg.CORBA.Any inc = r2.add_in_arg(); inc.insert_string(card); org.omg.CORBA.Any inc2 = r2.add_in_arg(); inc2.insert_double(amount);
Для этого сначала объект нужно поместить в список передаваемых аргументов, а потом присвоить ему значение.
После того как тип возвращаемого значения определен, а список передаваемых методу аргументов сформирован, метод может быть вызван:
r2.invoke();
Для того чтобы определить, не произошло ли при обработке запроса сервером исключений, их (исключения) можно извлечь с помощью вызова:
java.lang.Exception ex = r2.env().exception();
Для извлечения результата, возвращенного серверным методом, снова нужно обратиться к org.omg.CORBA.Request.
double result = r2.return_value().extract_double();
Таким образом, без использования IDL и соответствующих вспомогательных классов, генерируемых на его основе, разработчикам приходится выполнять гораздо больше рутинной работы. Так, приходится вручную осуществлять диспетчеризацию вызовов в серверном коде, а также вручную обрабатывать передаваемые и возвращаемые параметры. Похожие задачи, по упаковке аргументов и распаковке результата, приходится выполнять и на клиенте. Однако применение рассмотренной техники программирования позволяет решать ряд задач, которые невозможно решить с помощью систем, ориентированных на работу с объектами, интерфейсы которых известны на момент компиляции.
Компиляция и выполнение примера
Компиляция приложений, использующих DII или , ничем не отличается от компиляции ранее рассмотренных примеров.
Так же как для запуска других приложений CORBA, использующих сервис имен, требуется запуск этого сервиса:
tnameserv
Запуск компонентов приложения также не имеет особенностей:
G:\java com.asw.corba.ex3.BillingServiceServer IOR:000000000000002249444c3a4a61766149444c2f44534942696c6c696e6753 6572766963653a312e3000000000000001000000000000006e000102000000000c 3139322e3136382e312e3100134d000000000019afabcb0000000002b42a5d5400 000008000000000000000014000000000000020000000100000020000000000001 000100000002050100010001002000010109000000010001010000000026000000 020002 DSI: invoke called, op = addNewCard DSI: invoke called, op = addMoney DSI: invoke called, op = getCardBalance DSI: invoke called, op = subMoney DSI: invoke called, op = getCardBalance G:\java com.asw.corba.ex3.BillingServiceClient IOR:000000000000002249444c3a4a61766149444c2f44534942696c6c696e6753 6572766963653a312e3000000000000001000000000000006e000102000000000c 3139322e3136382e312e3100134d000000000019afabcb0000000002b42a5d5400 000008000000000000000014000000000000020000000100000020000000000001 000100000002050100010001002000010109000000010001010000000026000000 020002 Balance= 10.2 Balance= 2.0999999999999996
Рабочий каталог расположен в
Приложения, рассматриваемые в предыдущих разделах, строились исходя из предположения о том, что IDL перед началом разработки приложений.
Однако CORBA позволяет строить приложения, оперирующие объектами, интерфейсы которых неизвестны на момент компиляции приложения. Более того, возможно создание объектов, интерфейс которых будет изменяться в процессе их жизни (под интерфейсом мы понимаем совокупность методов объекта, которые может вызывать клиент). Данные возможности активно применяются при решении задач CORBA выступает в качестве "клея", связующего компоненты, которые выполнены в различных технологиях.
Соответствующие элементы технологии CORBA носят названия Dynamic Invocation Interface (DII) и Dynamic Skeleton Interface (DSI).
С помощью первой технологии ( DII ) клиенты могут формировать динамические вызовы методов объектов - формировать не в момент компиляции, а в процессе работы.
С помощью второй технологии ( ) серверные объекты могут регистрировать в системе новые методы, которые они будут реализовать, или изменять спецификацию старых. Для написания объектов с использованием этих технологий 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 }
Итак, метод invoke вызывается брокером запросов при вызове любого метода объекта, и его единственным параметром является ServerRequest - объект, содержащий всю необходимую информацию о вызове: имя вызываемого метода, список параметров и их типы. Поэтому в первую очередь проверяется имя вызываемого метода - оно может быть получено с помощью вызова op_name(),примененного к переданному ServerRequest.Далее, поскольку методы, как правило, принимают и возвращают аргументы, необходимо, во-первых, извлечь аргументы, переданные клиентом, а во-вторых, возвратить клиенту результат, если это необходимо.
Для извлечения из ServerRequest значений переданных клиентом аргументов необходимо выполнить следующие действия.
Создать список, в который затем будут считаны значения аргументов:
NVList nvlist = orb.create_list(0);
Заполнить список объектами, в которые будут считаны значения переданных клиентом аргументов. В данном случае список заполняется двумя объектами типа Any (это специальный тип CORBA, совместимый со всеми типами), которым присваиваются некоторые начальные значения (пустые строки) и которые заносятся в
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.
Класс BillingServiceServer
Класс BillingServiceServer служит для создания экземпляра BillingServiceImpl и его регистрации в сервисе имен. Он ничем не отличается от подобных классов, рассмотренных нами ранее.
1 package com.asw.corba.ex3;
2
3 import org.omg.CosNaming.*;
4 import org.omg.CORBA.*;
5
6 public class BillingServiceServer {
7
8 public static void main(String args[]) {
9 try {
10 // create and initialize the ORB
11 ORB orb = ORB.init(args, null);
12 // create servant and register it with the ORB
13 BillingServiceImpl BSRef = new BillingServiceImpl(orb);
14 orb.connect(BSRef);
15 System.out.println(BSRef);
16 org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService");
17 NamingContext ncRef = NamingContextHelper.narrow(objRef);
18 // bind the Object Reference in Naming
19 NameComponent nc = new NameComponent("BillingService", "");
20 NameComponent path[] = { nc };
21 ncRef.rebind(path, BSRef);
22 java.lang.Object sync = new java.lang.Object();
23 synchronized (sync) { sync.wait(); }
24 } catch (Exception e) {
25 System.err.println("ERROR: " + e);
26 e.printStackTrace(System.out);
27 }
28 }
29 }
Класс BillingServiceClient
Клиентский класс, так же как и серверный, не использует сгенерированные вспомогательные классы. Это означает, что необходимо вручную сформировать все вызовы к серверу, т.е. определить вызываемый метод, сформировать список передаваемых аргументов, осуществить вызов и получить результат.
1 package com.asw.corba.ex3;
2
3 import org.omg.CosNaming.*;
4 import org.omg.CORBA.*;
5
6 public class BillingServiceClient {
7 org.omg.CORBA.Object BSImpl;
8
9 ORB orb;
10
11 void testAddNewCard(String personName, String card) {
12 org.omg.CORBA.Request r2 = BSImpl._request("addNewCard");
13 r2.set_return_type(orb.get_primitive_tc(org.omg.CORBA.TCKind.tk_void));
14 org.omg.CORBA.Any inc = r2.add_in_arg();
15 inc.insert_string(personName);
16 org.omg.CORBA.Any inc2 = r2.add_in_arg();
17 inc2.insert_string(card);
18 r2.invoke();
19 java.lang.Exception ex = r2.env().exception();
20 if (ex instanceof org.omg.CORBA.UnknownUserException) {
21 org.omg.CORBA.UnknownUserException userEx = (org.omg.CORBA.UnknownUserException) ex;
22 }
23 }
24
25 void testAddMoney(String card, double amount) {
26 org.omg.CORBA.Request r2 = BSImpl._request("addMoney");
27 r2.set_return_type(orb.get_primitive_tc(org.omg.CORBA.TCKind.tk_void));
28 org.omg.CORBA.Any inc = r2.add_in_arg();
29 inc.insert_string(card);
30 org.omg.CORBA.Any inc2 = r2.add_in_arg();
31 inc2.insert_double(amount);
32 r2.invoke();
33 java.lang.Exception ex = r2.env().exception();
34 if (ex instanceof org.omg.CORBA.UnknownUserException) {
35 org.omg.CORBA.UnknownUserException userEx = (org.omg.CORBA.UnknownUserException) ex;
36 }
37 String result;
38 }
39
40 void testSubMoney(String card, double amount) {
41 org.omg.CORBA.Request r2 = BSImpl._request("subMoney");
42 r2.set_return_type(orb.get_primitive_tc(org.omg.CORBA.TCKind.tk_void));
43 org.omg.CORBA.Any inc = r2.add_in_arg();
44 inc.insert_string(card);
45 org.omg.CORBA.Any inc2 = r2.add_in_arg();
46 inc2.insert_double(amount);
47 r2.invoke();
48 java.lang.Exception ex = r2.env().exception();
49 if (ex instanceof org.omg.CORBA.UnknownUserException) {
50 org.omg.CORBA.UnknownUserException userEx = (org.omg.CORBA.UnknownUserException) ex;
51 }
52 String result;
53 }
54
55 double testGetCardBalance(String card) {
56 org.omg.CORBA.Request r2 = BSImpl._request("getCardBalance");
57 r2.set_return_type(orb.get_primitive_tc (org.omg.CORBA.TCKind.tk_double));
58 org.omg.CORBA.Any inc = r2.add_in_arg();
59 inc.insert_string(card);
60 r2.invoke();
61 java.lang.Exception ex = r2.env().exception();
62 if (ex instanceof org.omg.CORBA.UnknownUserException) {
63 org.omg.CORBA.UnknownUserException userEx = (org.omg.CORBA.UnknownUserException) ex;
64 }
65 double result;
66 result = r2.return_value().extract_double();
67 System.out.println("Balance= " + result);
68 return result;
69 }
70
71 public void doTest(String args[]) throws Exception {
72 orb = ORB.init(args, null);
73 org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService");
74 NamingContext ncRef = NamingContextHelper.narrow(objRef);
75 // resolve the Object Reference in Naming
76 NameComponent nc = new NameComponent("BillingService", "");
77 NameComponent path[] = { nc };
78 BSImpl = ncRef.resolve(path);
79 System.out.println(BSImpl);
80 this.testAddNewCard("Ivan", "1");
81 this.testAddMoney("1", 10.2);
82 this.testGetCardBalance("1");
83 this.testSubMoney("1", 8.1);
84 this.testGetCardBalance("1");
85 }
86
87 public static void main(String args[]) {
88 try {
89 BillingServiceClient bsc = new BillingServiceClient();
90 bsc.doTest(args);
91 } catch (Exception e) {
92 System.out.println("ERROR : " + e);
93 e.printStackTrace(System.out);
94 }
95 }
96 }
Формирование динамического вызова метода сервера осуществляется следующим образом.
У полученной у сервиса имен объектной ссылки (она имеет тип org.omg.CORBA.Object) вызовом метода request (в качестве аргумента этому методу передается имя вызываемого метода сервера) получаем org.omg.CORBA.Request - объект, который используется для осуществления запросов к серверу.
Первое, что необходимо указать, - тип возвращаемого методом значения:
r2.set_return_type(orb.get_primitive_tc (org.omg.CORBA.TCKind.tk_double));
Затем необходимо поместить в запрос передаваемые аргументы:
Заorg.omg.CORBA.Any inc = r2.add_in_arg(); inc.insert_string(card); org.omg.CORBA.Any inc2 = r2.add_in_arg(); inc2.insert_double(amount);
Для этого сначала объект нужно поместить в список передаваемых аргументов, а потом присвоить ему значение.
После того как тип возвращаемого значения определен, а список передаваемых методу аргументов сформирован, метод может быть вызван:
r2.invoke();
Для того чтобы определить, не произошло ли при обработке запроса сервером исключений, их (исключения) можно извлечь с помощью вызова:
java.lang.Exception ex = r2.env().exception();
Для извлечения результата, возвращенного серверным методом, снова нужно обратиться к org.omg.CORBA.Request.
double result = r2.return_value().extract_double();
Таким образом, без использования IDL и соответствующих вспомогательных классов, генерируемых на его основе, разработчикам приходится выполнять гораздо больше рутинной работы. Так, приходится вручную осуществлять диспетчеризацию вызовов в серверном коде, а также вручную обрабатывать передаваемые и возвращаемые параметры. Похожие задачи, по упаковке аргументов и распаковке результата, приходится выполнять и на клиенте. Однако применение рассмотренной техники программирования позволяет решать ряд задач, которые невозможно решить с помощью систем, ориентированных на работу с объектами, интерфейсы которых известны на момент компиляции.
Компиляция и выполнение примера
Компиляция приложений, использующих DII или , ничем не отличается от компиляции ранее рассмотренных примеров.
Так же как для запуска других приложений CORBA, использующих сервис имен, требуется запуск этого сервиса:
tnameserv
Запуск компонентов приложения также не имеет особенностей:
G:\java com.asw.corba.ex3.BillingServiceServer IOR:000000000000002249444c3a4a61766149444c2f44534942696c6c696e6753 6572766963653a312e3000000000000001000000000000006e000102000000000c 3139322e3136382e312e3100134d000000000019afabcb0000000002b42a5d5400 000008000000000000000014000000000000020000000100000020000000000001 000100000002050100010001002000010109000000010001010000000026000000 020002 DSI: invoke called, op = addNewCard DSI: invoke called, op = addMoney DSI: invoke called, op = getCardBalance DSI: invoke called, op = subMoney DSI: invoke called, op = getCardBalance G:\java com.asw.corba.ex3.BillingServiceClient IOR:000000000000002249444c3a4a61766149444c2f44534942696c6c696e6753 6572766963653a312e3000000000000001000000000000006e000102000000000c 3139322e3136382e312e3100134d000000000019afabcb0000000002b42a5d5400 000008000000000000000014000000000000020000000100000020000000000001 000100000002050100010001002000010109000000010001010000000026000000 020002 Balance= 10.2 Balance= 2.0999999999999996
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.