summaryrefslogtreecommitdiff
path: root/TAO/docs/tutorials/Quoter/Simple/Server/index.html
blob: 92f4a5f90bad76d12a0b0c2f2aa7a743d5688cb0 (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
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
  <head>
    <title>Introduction - A very simple server</title>
    <!-- $Id$ -->
  </head>

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

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

    <P>Now that we know how to implement a
      <A HREF="../Client/index.html">simple client</A>, we need to
      implement a server to test it out.
      We have to provide implementations for both the <CODE>Stock</CODE>
      and <CODE>Stock_Factory</CODE> interfaces,
      and then create an executable that incorporates those implementations.
    </P>

    <H3>Implementing the <CODE>Stock</CODE> interface</H3>

    <P>To keep things simple, let's implement a <CODE>Stock</CODE>
      object with a fixed price.  The constructor will receive all the
      parameters:
    </P>
<PRE>
class Quoter_Stock_i : public POA_Quoter::Stock {
public:
  Quoter_Stock_i (const char *symbol,
                  const char *full_name,
                  CORBA::Double price);

private:
  std::string symbol_;
  std::string full_name_;
  CORBA::Double price_;
};
</PRE>
    <P>In a server, CORBA objects and functions are implemented and
      represented by programming language data and functions. These 
      programming entities that implement and represent CORBA objects 
      are called <I>servants</I>. <I>Object Adapters</I> link the world of 
      CORBA objects to the world of programming language servants. They 
      provide services for creation of CORBA objects and their object 
      references and for dispatching requests to the appropriate
      servants. 
    </P>
    <P>Notice the name of the base class.  TAO implements the CORBA 2.2
      specification, which includes the Portable Object Adapter (hence
      the POA prefix).  This new Object Adapter fixes many problems
      with the previous versions of the CORBA specification, where the
      so-called Basic Object Adapter was used.  Unfortunately, the
      specification was ambiguous and lead to incompatible (yet
      compliant) implementations.
      Code based on the POA, and conforming to the CORBA 2.2
      specification, is almost completely portable,
      the only incompatibilities arising from the names of the
      generated header files and and other minor things.
      Those problems can be easily wrapped in helper classes, and the
      file names can be controlled through IDL compiler options in
      most cases.
    </P>
    <P>A server application may contain multiple POA instances, but all 
      server applications have at least one POA called the <I>RootPOA</I>.
    <P>We have to implement the operations and attributes:
    </P>
<PRE>
class Quoter_Stock_i : public POA_Quoter::Stock {
public:
  // some details omitted
  char *symbol () throw (CORBA::SystemException);
  char *full_name () throw (CORBA::SystemException);
  CORBA::Double price () throw (CORBA::SystemException);
};

// In the .cpp file:
char *
Quoter_Stock_i::symbol () throw (CORBA::SystemException)
{
  return CORBA::string_dup (this->symbol_.c_str ());
}
</PRE>
    <P>The other attributes and methods are similar, so we don't
      reproduce them here.
    </P>
    <P>The first question is what are those <CODE>throw()</CODE>
      specifications doing there?  Any CORBA operation or attribute
      can raise a <CODE>CORBA::SystemException</CODE>.  The IDL compiler
      must generate a throw specification that includes the CORBA
      system exceptions and any user exceptions listed in the
      <CODE>raise</CODE> clause.  In turn, the C++ specification requires
      that any derived classes cannot add exceptions to a throw
      specification, so you must have a throw specification in your
      methods, either including <CODE>CORBA::SystemException</CODE> or
      empty.
    </P>

    <H4>Memory management rules for arguments</H4>

    <P>It is important to copy the strings before returning them,
      because the ORB will use <CODE>CORBA::string_free</CODE> to release
      them. The rationale is that over the network, the string must be
      copied anyway, hence, the client must be responsible for releasing
      the received string.  When both client and servers are in the same
      address space the ORB can optimize the path and invoke the server
      operation directly, without marshaling or demarshaling.  If the
      client is going to work with both local and remote servers, it
      should always expect to own the string.  In consequence, the server
      implementation must always allocate a copy and return the copy,
      because the server-side must also work identically for local and
      remote clients.  The memory management rules in CORBA are a bit
      subtle, but there are some simple rules to follow:
      <UL>
        <LI>You must make a copy of the memory that you return.  The
          caller is going to release it.
        </LI>
        <LI>Conversely, you must release the memory returned to you.  The
        callee made a copy.
        </LI>
        <LI>You don't own the memory that you receive as input
        arguments,
        you can only use it for the duration of the call.
        You must make a copy if you want to hold a reference to it
        after you return.
        </LI>
      </UL>
      The complete memory management rules can be found in the Henning and
      Vinoski book or the CORBA specification.
    </P>

    <P>Typing all this code seems tedious.  Can't the IDL compiler
      help with this?  After all, it seems as if the method declarations
      are completely specified!  The answer is yes, TAO's IDL compiler
      can generate empty implementations that you can modify.  Simply
      use the <KBD>-GI</KBD> option:
<PRE>
$ $ACE_ROOT/TAO/TAO_IDL/tao_idl -GI Quoter.idl
</PRE>
      The empty implementations are generated in the
      <CODE>QuoterI.h</CODE> and <CODE>QuoterI.cpp</CODE> files.
      Be advised that the <CODE>-GI</CODE> option overwrites these files
      every time, so it is better to copy your implementation to
      another file.
    </P>

    <H3>The Stock Factory implementation</H3>

    <P>Our first implementation of the factory will serve only two
      stocks, "RHAT" and "MSFT":
    </P>
<PRE>
class Quoter_Stock_Factory_i : public POA_Quoter::Stock_Factory
{
public:
  Quoter_Stock_Factory ();

  Quoter::Stock_ptr get_stock (const char *symbol)
    throw (Quoter::Invalid_Stock_Symbol);

private:
  Quoter_Stock_i rhat_;
  Quoter_Stock_i msft_;
};
</PRE>

    <P>The implementation of the <CODE>get_stock()</CODE> method is
      simple, just compare the symbol name and return the appropriate
      object reference:
    </P>
<PRE>
Quoter::Stock_ptr
Quoter_Stock_Factory_i::get_stock (const char *symbol)
    throw (Quoter::Invalid_Stock_Symbol)
{
  if (strcmp (symbol, "RHAT") == 0) {
    return this->rhat_._this();
  } else if (strcmp (symbol, "MSFT") == 0) {
    return this->msft_._this ();
  }
  throw Quoter::Invalid_Stock_Symbol ();
}
</PRE>

    <P>So what is that <CODE>_this()</CODE> method?  In the POA mapping
      the client-side stubs and server-side skeletons are not related
      through inheritance.  You must either explicitly activate the
      servant (your implementation object) or use <CODE>_this()</CODE> to
      activate it with its default POA.  <CODE>_this()</CODE> creates and 
      registers a CORBA object under the RootPOA, and returns the created 
      object reference for the new object. We will discuss more about
      explicit and implicit activation later, but at this point it is
      important to remove any thoughts about converting pointers to
      servants to object references or vice-versa, it just does not
      work that way.
    </P>

    <H3>Implementing a CORBA server</H3>

    <P>Now that we have all the object implementations in place, we
      must create the server executable.  We start with the ORB
      initialization:
    </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>On startup, the ORB starts the POA in the {<em>holding state</em>},
      where all requests received are not processed until the POA is
      activated.  Meanwhile the requests are stored to some
      implementation limit.  TAO sets this limit to 0, because queueing
      is a severe source of overhead and unpredictability in real-time
      systems.
    </P>
    <P>What does this means for us? Well, we have to activate the POA.
      The process is a bit tedious.  First we gain access to the
      RootPOA:
<PRE>
    CORBA::Object_var poa_object =
      orb->resolve_initial_references ("RootPOA");
    PortableServer::POA_var poa =
      PortableServer::POA::_narrow (poa_object.in ());
</PRE>
    <P><CODE>resolve_initial_references()</CODE> is used to bootstrap
      all kinds of services, like the Naming Service and the Trading
      Service, but it is also used to gain access to other ORB
      interfaces, such as the RootPOA, the Current objects, and the
      Policy Managers.
    </P>
    <P>Now that we have gained access to the Root POA, we must obtain
      its POA manager.  The POA managers provide interfaces to activate
      and deactivate one or more POAs:
    </P>
<PRE>
    PortableServer::POAManager_var poa_manager =
      poa->the_POAManager ();
</PRE>
    <P>and now we activate the POA:
    </P>
<PRE>
    poa_manager->activate ();
</PRE>

    <P>The shutdown process is similar to the client side, but now we
      must also remember to destroy the POA.  Putting all the code
      above together, we get:
    </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! */);
    CORBA::Object_var poa_object =
      orb->resolve_initial_references ("RootPOA");
    PortableServer::POA_var poa =
      PortableServer::POA::_narrow (poa_object.in ());
    PortableServer::POAManager_var poa_manager =
      poa->the_POAManager ();
    poa_manager->activate ();

    // The application code goes here!

    // Destroy the POA, waiting until the destruction terminates
    poa->destroy (1, 1);
    orb->destroy ();
  }
  catch (CORBA::Exception &ex) {
    std::cerr << "CORBA exception raised!" << std::endl;
  }
  return 0;
}
</PRE>

    <P>Now we create an instance of our stock factory implementation
      and activate it using <CODE>_this()</CODE>
    </P>
<PRE>
    Quoter_Stock_Factory_i stock_factory_i;

    Quoter::Stock_Factory_var stock_factory =
      stock_factory_i._this ();
</PRE>
    <P>Next we convert the object reference into an IOR string, so it
      can be used by the client:
    </P>
<PRE>
    CORBA::String_var ior = orb->object_to_string (stock_factory.in ());
    std::cerr << ior.in () << std::endl;
</PRE>

    <P>There is only one final detail.  We must run the ORB event loop
      to start processing requests from the client:
    </P>
<PRE>
    orb->run ();
</PRE>

    <P>There are many details that we have left out from this server,
      such as how to terminate the event loop, how to perform servant
      memory management, orderly deactivation of servants, and the fact
      is that it is not very flexible, but we have covered a number
      of other things, and more importantly we can test the client
      now!
    </P>

    <H3>Exercise 1</H3>

    <P>Flesh out the implementation.  You don't have to do it from
      scratch, as we provide you with the following files:
      <A HREF="Stock_i.h">Stock_i.h</A>,
      <A HREF="Stock_i.cpp">Stock_i.cpp</A>,
      <A HREF="Stock_Factory_i.h">Stock_Factory_i.h</A>
      <A HREF="Stock_Factory_i.cpp">Stock_Factory_i.cpp</A>,
      <A HREF="../Quoter.idl">Quoter.idl</A>
      and the always useful
      <A HREF="GNUmakefile.Quoter_Simple_Server">Makefile</A>
    </P>

    <H4>Solution</H4>

    <P>Compare your solution with
      <A HREF="server.cpp">server.cpp</A>.
    </P>

    <H3>Testing</H3>

    <P>To test this application we need a
      <A HREF="../Client/index.html">client</A>.
      We just run both of them:
<PRE>
$ server > ior_file
$ client file://ior_file MSFT RHAT
</PRE>
      Also test invalid symbols!
    </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 15:03:38 PDT 2001
<!-- hhmts end -->
  </body>
</html>