1 <!DOCTYPE HTML PUBLIC
"-//IETF//DTD HTML//EN">
4 <title>Introduction - A very simple client
</title>
13 <h3>Introduction - A very simple client
</h3>
15 <P>We will start with a reasonably simple IDL interface: we want
16 to build a stock quoter server, some interface to query the
17 prices of stock. To make life interesting we will use a
18 different CORBA object for each stock. This may sound like
19 overkill, but it will motivate a number of elements that are
20 interesting to learn at the start.
23 <H3>Defining the IDL interfaces
</H3>
25 <P>At the very least we want an operation to query the stock
33 <P>but stocks usually have symbols and full names, so why not add
34 a couple of attributes to query them:
40 readonly attribute string symbol;
41 readonly attribute string full_name;
44 <P>We also need some interface to gain access to the
45 <CODE>Stock
</CODE> object references from their symbols.
46 Usually we call this kind of interface a
<EM>Factory
</EM>,
47 and it looks like this:
50 interface Stock_Factory {
51 Stock get_stock (in string stock_symbol);
54 <P>Notice how arguments have a
<EM>direction
</EM>: they are
55 qualified as
<EM>input only (
<CODE>in
</CODE>)
</EM>,
56 <EM>output only (
<CODE>out
</CODE>)
</EM>,
57 or
<EM>input-output (
<CODE>inout
</CODE>)
</EM> arguments.
58 There is a problem, though: what happens if the stock symbol is
59 invalid? The CORBA way is to raise an exception:
62 exception Invalid_Stock_Symbol {};
64 <P>and then make the exception part of the
65 <CODE>Stock_Factory
</CODE> interface:
68 interface Stock_Factory {
69 Stock get_stock (in string stock_symbol)
70 raises (Invalid_Stock_Symbol);
74 <P>Finally we put all these IDL constructs in a module to avoid
75 namespace pollution to obtain the
76 <A HREF=
"../Quoter.idl">Quoter.idl
</A> file.
79 <H3>The Generated Files
</H3>
81 <P>Let's take a minute to look at the generated code.
82 You don't need to do this often, in fact you rarely have to do
83 it at all. But doing it once is educative and can demystify the
84 role of the IDL compiler.
86 <P>To generate the code you must
87 invoke the IDL compiler, like
91 $ $TAO_ROOT/TAO_IDL/tao_idl Quoter.idl
93 <P>The complete documentation of the IDL compiler and its options
95 <A HREF=
"../../../../compiler.html">compiler.html
</A>.
96 Naturally this file is included in the distribution.
99 <P>TAO generates
9 files for each IDL file.
100 <CODE>QuoterC.h
</CODE>,
<CODE>QuoterC.inl
</CODE>
101 and
<CODE>QuoterC.cpp
</CODE> contain the client-side interfaces.
102 Notice that the inline functions are in a separate file so you
103 can optionally compile them out-of-line for smaller code.
104 Pure clients only need to link the object file
105 generated from
<CODE>QuoterC.cpp
</CODE>.
108 Similarly,
<CODE>QuoterS.h
</CODE>,
109 and
<CODE>QuoterS.cpp
</CODE> contain the server-side
110 <EM>skeletons
</EM>. Servers must link the object files generated
111 from
<CODE>QuoterS.cpp
</CODE> <STRONG>and
</STRONG> <CODE>QuoterC.cpp
</CODE>.
114 Finally,
<CODE>QuoterS_T.h
</CODE>,
<CODE>QuoterS_T.inl
</CODE>
115 and
<CODE>QuoterS_T.cpp
</CODE> contain the
<EM>TIE
</EM> classes.
116 These are the standard (after the CORBA
2.2 spec) skeletons based
117 on composition instead of inheritance.
118 They are in separate files only because some compilers cannot
119 handle mixed template and non-template code in the same source
120 file. You
<STRONG>do not
</STRONG> need to compile these files on any
122 However, the files are required to compile
123 <CODE>QuoterS.cpp
</CODE>.
124 Also notice that if your platform does not support namespaces,
125 then you may be unable to use the TIE approach for some IDL
129 <P>All the extensions and suffixes discussed above can be modified
130 using options of the IDL compiler; check the documentation for
131 more details. Notice, though, that you should use consistent
132 extensions across your project, otherwise you may have problems
133 with some
<CODE>#include
</CODE> directives in your IDL source.
136 <H3>Building a simple client
</H3>
138 <P>With our simple IDL interface ready, we want to start with a
139 simple client. The first thing to do in any CORBA client or
140 server is initialize the ORB:
143 int main (int argc, char* argv[])
146 // First initialize the ORB, that will remove some arguments...
148 CORBA::ORB_init (argc, argv,
149 "" /* the ORB name, it can be anything! */);
151 <P>IDL supports variable-length types whose sizes are not known
152 at compile time, hence they must be dynamically allocated at run
153 time.
<CODE>_var
</CODE> types relieve us of the explicit memory
154 management of the variable-length types and thus hide the
155 differences between fixed and variable-length structured types.
157 <P>Since the ORB initialization can fail, and in fact, any CORBA
158 operation can raise a
<CODE>CORBA::SystemException
</CODE> we use
159 a
<CODE>try/catch
</CODE> block to check for any failures.
160 Needless to say, this is very naive; some failures can be
161 temporary, and we should have a better way to recover from
162 errors, but this is enough for our example.
163 In consequence, at the end of
<CODE>main()
</CODE> we catch all
164 kinds of CORBA exceptions:
168 catch (const CORBA::Exception &ex) {
169 std::cerr <<
"CORBA exception raised!" << std::endl;
174 <P>We must not forget that the ORB is a resource that must be
175 released by the application. Until CORBA
2.3 there was no
176 standard way to do this. TAO has adopted the new specification,
177 so our client should really look like this:
180 int main (int argc, char* argv[])
183 // First initialize the ORB, that will remove some arguments...
185 CORBA::ORB_init (argc, argv,
186 "" /* the ORB name, it can be anything! */);
188 // the real code goes here!
192 catch (const CORBA::Exception &ex) {
193 std::cerr <<
"CORBA exception raised!" << std::endl;
199 <P>Just a few words about the ORB name: The spec requires the ORB
200 to return the same ORB pointer if the same ORB id is used in
201 <CODE>CORBA::init
</CODE>, and
202 the implementation is free to return the same pointer even if
203 different ids are used.
204 Usually this is not a problem, as most applications instantiate a
205 single ORB. TAO is one of the few CORBA implementations that
206 actually supports multiple ORB pointers. This can be important
207 for real-time applications where each ORB executes at a different
211 <P>Now that we have the ORB pointer, we can start bootstrapping the
212 application. Normally we would use the Naming Service,
213 Trading Service, or the Interoperable Naming Service to locate
214 the stock factory, but for simplicity, let us use just an IOR
215 string passed in the first argument.
217 <P>The easiest way is to use the first argument to get the string,
218 and then use
<CODE>string_to_object()
</CODE> to convert it into an
222 CORBA::Object_var factory_object =
223 orb-
>string_to_object (argv[
1]);
225 Quoter::Stock_Factory_var factory =
226 Quoter::Stock_Factory::_narrow (factory_object.in ());
228 <P>The
<CODE>_narrow()
</CODE> is used to test if a reference
229 is of the specified type. If the reference is of the specified
230 type, it returns a non-nil reference, else it returns a nil.
232 <P>There are a few interesting things about TAO: First, it supports
233 the
<CODE>file:
</CODE> scheme for object references, so the first
234 argument could be
<CODE>file://a_file_name
</CODE>. In that case,
235 the ORB will open the file named
<CODE>"a_file_name"</CODE> and
236 read the IOR from that file.
237 TAO also supports the
<CODE>corbaloc:
</CODE> scheme, for example
238 <CODE>corbaloc:iiop:
1.1@ace.cs.wustl.edu:
12345/Stock_Factory
</CODE>.
239 So using a string can be a very powerful bootstrapping protocol.
241 <P>Before we go any further, at this point we are using interfaces
242 generated by the IDL compiler, so we must include the correct
248 Notice that this is all you need to include; the IDL compiler
249 generates code that includes all the required internal header
251 When you use TAO services, don't forget to include their
252 corresponding header files too.
255 <P>Another interesting TAO feature is the support for
256 <CODE>_unchecked_narrow()
</CODE>.
257 This is part of the CORBA Messaging specification and
258 essentially performs the same work as
<CODE>_narrow()
</CODE>,
259 but it does not check the types remotely.
260 If you have compile time knowledge that ensures the correctness
261 of the narrow operation, it is more efficient to use the
265 <P>Now we can use the rest of the arguments to obtain the stock
269 for (int i =
2; i != argc; ++i) {
271 // Get the stock object
272 Quoter::Stock_var stock =
273 factory-
>get_stock (argv[i]);
278 <P>Complete the client implementation. It should be easy at this
279 point, but it will give you a chance to set up your environment
280 and become familiar with the basics of building a TAO
283 <P>You don't need to do everything.
284 The
<A HREF=
"../Quoter.idl">Quoter.idl
</A> file and
285 a
<A HREF=
"Quoter_Simple_Client.mpc">MPC file
</A>
287 implement the
<CODE>client.cpp
</CODE> file.
288 Cut & paste the ORB initialization code, and anything you find
289 useful from above (you can even cheat and look at the solution,
290 but it is going to be some really boring
30 minutes if you do!).
296 <A HREF=
"client.cpp">client.cpp
</A> file; it should
297 not be much different from yours. Count the number of lines in
298 your client, the idl file and the
<CODE>QuoterC.*
</CODE> files. Do
299 you want to write all that code over again?
304 <P>To test this application we need a server working, a
305 good excuse to go to the next
306 <A HREF=
"../Server/index.html">lesson
</A> in the tutorial.
310 <address><a href=
"mailto:coryan@cs.wustl.edu">Carlos O'Ryan
</a></address>
311 <!-- Created: Sat Nov 27 15:47:01 CST 1999 -->
313 Last modified: Sun Apr
1 14:
55:
08 PDT
2001