summaryrefslogtreecommitdiff
path: root/TAO/docs/tutorials/Quoter/Simple/Client/index.html
blob: ef4e599869f9bcbccb8a116c01637ed3c5123a74 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
  <head>
    <title>Introduction - A very simple client</title>
    <!--  -->
  </head>

  <BODY text = "#000000"
    link="#000fff"
    vlink="#ff0f0f"
    bgcolor="#ffffff">

    <h3>Introduction - A very simple client</h3>

    <P>We will start with a reasonably simple IDL interface: we want
      to build a stock quoter server, some interface to query the
      prices of stock.  To make life interesting we will use a
      different CORBA object for each stock.  This may sound like
      overkill, but it will motivate a number of elements that are
      interesting to learn at the start.
    </P>

    <H3>Defining the IDL interfaces</H3>

    <P>At the very least we want an operation to query the stock
      price, as in:
    </P>
<PRE>
    interface Stock {
      double price ();
    };
</PRE>
    <P>but stocks usually have symbols and full names, so why not add
      a couple of attributes to query them:
    </P>
<PRE>
    interface Stock {
      double price ();

      readonly attribute string symbol;
      readonly attribute string full_name;
    };
</PRE>
    <P>We also need some interface to gain access to the
      <CODE>Stock</CODE> object references from their symbols.
      Usually we call this kind of interface a <EM>Factory</EM>,
      and it looks like this:
    </P>
<PRE>
  interface Stock_Factory {
    Stock get_stock (in string stock_symbol);
  };
</PRE>
    <P>Notice how arguments have a <EM>direction</EM>:  they are
      qualified as <EM>input only (<CODE>in</CODE>)</EM>,
      <EM>output only (<CODE>out</CODE>)</EM>,
      or <EM>input-output (<CODE>inout</CODE>)</EM> arguments.
      There is a problem, though:  what happens if the stock symbol is
      invalid?  The CORBA way is to raise an exception:
    </P>
<PRE>
  exception Invalid_Stock_Symbol {};
</PRE>
    <P>and then make the exception part of the
      <CODE>Stock_Factory</CODE> interface:
    </P>
<PRE>
  interface Stock_Factory {
    Stock get_stock (in string stock_symbol)
      raises (Invalid_Stock_Symbol);
  };
</PRE>

    <P>Finally we put all these IDL constructs in a module to avoid
      namespace pollution to obtain the
      <A HREF="../Quoter.idl">Quoter.idl</A> file.
    </P>

    <H3>The Generated Files</H3>

    <P>Let's take a minute to look at the generated code.
      You don't need to do this often, in fact you rarely have to do
      it at all.  But doing it once is educative and can demystify the
      role of the IDL compiler.
    </P>
    <P>To generate the code you must
      invoke the IDL compiler, like
      this:
    </P>
<PRE>
$ $TAO_ROOT/TAO_IDL/tao_idl Quoter.idl
</PRE>
    <P>The complete documentation of the IDL compiler and its options
      are included in
      <A HREF="../../../../compiler.html">compiler.html</A>.
      Naturally this file is included in the distribution.
    </P>

    <P>TAO generates 9 files for each IDL file.
      <CODE>QuoterC.h</CODE>, <CODE>QuoterC.inl</CODE>
      and <CODE>QuoterC.cpp</CODE> contain the client-side interfaces.
      Notice that the inline functions are in a separate file so you
      can optionally compile them out-of-line for smaller code.
      Pure clients only need to link the object file
      generated from <CODE>QuoterC.cpp</CODE>.
    </P>
    <P>
      Similarly, <CODE>QuoterS.h</CODE>,
      and <CODE>QuoterS.cpp</CODE> contain the server-side
      <EM>skeletons</EM>. Servers must link the object files generated
      from <CODE>QuoterS.cpp</CODE> <STRONG>and</STRONG> <CODE>QuoterC.cpp</CODE>.
    </P>
    <P>
      Finally, <CODE>QuoterS_T.h</CODE>, <CODE>QuoterS_T.inl</CODE>
      and <CODE>QuoterS_T.cpp</CODE> contain the <EM>TIE</EM> classes.
      These are the standard (after the CORBA 2.2 spec) skeletons based
      on composition instead of inheritance.
      They are in separate files only because some compilers cannot
      handle mixed template and non-template code in the same source
      file.  You <STRONG>do not</STRONG> need to compile these files on any
      platform.
      However, the files are required to compile
      <CODE>QuoterS.cpp</CODE>.
      Also notice that if your platform does not support namespaces,
      then you may be unable to use the TIE approach for some IDL
      interfaces.
    </P>

    <P>All the extensions and suffixes discussed above can be modified
      using options of the IDL compiler; check the documentation for
      more details.  Notice, though, that you should use consistent
      extensions across your project, otherwise you may have problems
      with some <CODE>#include</CODE> directives in your IDL source.
    </P>

    <H3>Building a simple client</H3>

    <P>With our simple IDL interface ready, we want to start with a
      simple client.  The first thing to do in any CORBA client or
      server is initialize the ORB:
    </P>
<PRE>
int main (int argc, char* argv[])
{
  try {
    // First initialize the ORB, that will remove some arguments...
    CORBA::ORB_var orb =
      CORBA::ORB_init (argc, argv,
                       "" /* the ORB name, it can be anything! */);
</PRE>
    <P>IDL supports variable-length types whose sizes are not known
      at compile time, hence they must be dynamically allocated at run
      time. <CODE>_var</CODE> types relieve us of the explicit memory
      management of the variable-length types and thus hide the
      differences between fixed and variable-length structured types.
    </P>
    <P>Since the ORB initialization can fail, and in fact, any CORBA
      operation can raise a <CODE>CORBA::SystemException</CODE> we use
      a <CODE>try/catch</CODE> block to check for any failures.
      Needless to say, this is very naive; some failures can be
      temporary, and we should have a better way to recover from
      errors, but this is enough for our example.
      In consequence, at the end of <CODE>main()</CODE> we catch all
      kinds of CORBA exceptions:
    </P>
<PRE>
  }
  catch (const CORBA::Exception &ex) {
    std::cerr << "CORBA exception raised!" << std::endl;
  }
  return 0;
}
</PRE>
    <P>We must not forget that the ORB is a resource that must be
      released by the application.  Until CORBA 2.3 there was no
      standard way to do this. TAO has adopted the new specification,
      so our client should really look like this:
    </P>
<PRE>
int main (int argc, char* argv[])
{
  try {
    // First initialize the ORB, that will remove some arguments...
    CORBA::ORB_var orb =
      CORBA::ORB_init (argc, argv,
                       "" /* the ORB name, it can be anything! */);

    // the real code goes here!

    orb->destroy ();
  }
  catch (const CORBA::Exception &ex) {
    std::cerr << "CORBA exception raised!" << std::endl;
  }
  return 0;
}
</PRE>

    <P>Just a few words about the ORB name:  The spec requires the ORB
      to return the same ORB pointer if the same ORB id is used in
      <CODE>CORBA::init</CODE>, and
      the implementation is free to return the same pointer even if
      different ids are used.
      Usually this is not a problem, as most applications instantiate a
      single ORB.  TAO is one of the few CORBA implementations that
      actually supports multiple ORB pointers.  This can be important
      for real-time applications where each ORB executes at a different
      priority.
    </P>

    <P>Now that we have the ORB pointer, we can start bootstrapping the
      application.  Normally we would use the Naming Service,
      Trading Service, or the Interoperable Naming Service to locate
      the stock factory, but for simplicity, let us use just an IOR
      string passed in the first argument.
    </P>
    <P>The easiest way is to use the first argument to get the string,
      and then use <CODE>string_to_object()</CODE> to convert it into an
      object reference:
    </P>
<PRE>
    CORBA::Object_var factory_object =
      orb->string_to_object (argv[1]);

    Quoter::Stock_Factory_var factory =
      Quoter::Stock_Factory::_narrow (factory_object.in ());
</PRE>
    <P>The <CODE>_narrow()</CODE> is used to test if a reference
      is of the specified type. If the reference is of the specified
      type, it returns a non-nil reference, else it returns a nil.
    </P>
    <P>There are a few interesting things about TAO:  First, it supports
      the <CODE>file:</CODE> scheme for object references, so the first
      argument could be <CODE>file://a_file_name</CODE>.  In that case,
      the ORB will open the file named <CODE>"a_file_name"</CODE> and
      read the IOR from that file.
      TAO also supports the <CODE>corbaloc:</CODE> scheme, for example
      <CODE>corbaloc:iiop:1.1@ace.cs.wustl.edu:12345/Stock_Factory</CODE>.
      So using a string can be a very powerful bootstrapping protocol.
    </P>
    <P>Before we go any further, at this point we are using interfaces
      generated by the IDL compiler, so we must include the correct
      header file!
    </P>
<PRE>
#include "QuoterC.h"
</PRE>
      Notice that this is all you need to include; the IDL compiler
      generates code that includes all the required internal header
      files.
      When you use TAO services, don't forget to include their
      corresponding header files too.
    </P>

    <P>Another interesting TAO feature is the support for
      <CODE>_unchecked_narrow()</CODE>.
      This is part of the CORBA Messaging specification and
      essentially performs the same work as <CODE>_narrow()</CODE>,
      but it does not check the types remotely.
      If you have compile time knowledge that ensures the correctness
      of the narrow operation, it is more efficient to use the
      unchecked version.
    </P>

    <P>Now we can use the rest of the arguments to obtain the stock
      objects:
    </P>
<PRE>
    for (int i = 2; i != argc; ++i) {
      try {
        // Get the stock object
        Quoter::Stock_var stock =
          factory->get_stock (argv[i]);
</PRE>

    <H3>Exercise 1</H3>

    <P>Complete the client implementation.  It should be easy at this
      point, but it will give you a chance to set up your environment
      and become familiar with the basics of building a TAO
      application.
    </P>
    <P>You don't need to do everything.
      The <A HREF="../Quoter.idl">Quoter.idl</A> file and
      a <A HREF="Quoter_Simple_Client.mpc">MPC file</A>
      are provided.  Just
      implement the <CODE>client.cpp</CODE> file.
      Cut & paste the ORB initialization code, and anything you find
      useful from above (you can even cheat and look at the solution,
      but it is going to be some really boring 30 minutes if you do!).
    </P>

    <H4>Solution</H4>

    <P>Look at the
      <A HREF="client.cpp">client.cpp</A> file; it should
      not be much different from yours.  Count the number of lines in
      your client, the idl file and the <CODE>QuoterC.*</CODE> files.  Do
      you want to write all that code over again?
    </P>

    <H3>Testing</H3>

    <P>To test this application we need a server working, a
      good excuse to go to the next
      <A HREF="../Server/index.html">lesson</A> in the tutorial.
    </P>

    <hr>
    <address><a href="mailto:coryan@cs.wustl.edu">Carlos O'Ryan</a></address>
<!-- Created: Sat Nov 27 15:47:01 CST 1999 -->
<!-- hhmts start -->
Last modified: Sun Apr  1 14:55:08 PDT 2001
<!-- hhmts end -->
  </body>
</html>