summaryrefslogtreecommitdiff
path: root/TAO/docs/tutorials/Quoter/On_Demand_Activation/index.html
blob: 63e4fa14445c267561e95349c15a916c118e4a31 (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

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
  <head>
    <title>Servant Managers</title>
    <!-- $Id$ -->
  </head>

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

    <h1>Servant Managers</h1>
    <P>In our <a href=../AMI/index.html>previous example</a>, we
      extended our <a href=../Simple/Client/client.cpp>simple client</a>  
      using synchronous method invocation to handle asynchronous 
      requests: Asynchronous Method Invocation by using 
      the reply handlers.
    </P>
    <P>In applications which have many objects, activating
      all of them all the time would be unnecessary
      and also might require too much memory or too many database
      lookups. For such applications, the POA provides an option 
      for the application to supply servant managers that can
      dynamically supply servants on a per-request basis.
    </P>
    <p> A servant manager is a call-back object that the application 
      registers with a POA. When the POA attempts to determine the
      servant associated with a particular request, it calls back the
      application's servant manager to obtain the servant. To be able
      to register a servant manager with the POA, the 
      <CODE>RequestProcessingPolicyValue</CODE>, which controls the
      matching of requests to servants, is to be set to
      <CODE>USE_SERVANT_MANAGER</CODE>.
    </P>
    <P>There are two types of servant managers depending on whether the POA
      retains the associations of objects to servants in its Active
      Object Map or not. This is determined by the value of the 
      <CODE>ServantRetentionPolicy</CODE> set when the
      POA is created. If the value of this policy is set as RETAIN,
      the POA retains the associations, and if the policy value is set
      to be NON_RETAIN, the POA doesn't retain any associations between
      the object and the servant. 
    </P>
    <P>For a POA with the RETAIN value, the servant manager must
      activate the servant associated with the object. This would need
      the servant manager object to support the ServantActivator
      interface. In the case of a POA with the NON_RETAIN value set,
      our servant manager object should be able to locate the servant
      for the requested object and then invoke it. 
    </P>
    <P>In this example, let's use a servant locator to locate the
      servant associated with our Stock_Factory object when a request
      is invoked on this object. 
    </P>
    <H3>The Stock Factory Locator Implementation</H3>
    <P>Our implementation of the Stock_Factory_Locator_i will help 
      us find the Quoter_Stock_Factory servant. 
    </P>
    <P>A servant Locator interface provides two operations: preinvoke
      and postinvoke. The preinvoke operation is invoked to obtain the
      servant to dispatch the request to. The servant returned by
      the preinvoke is used only for a single request. The postinvoke 
      operation is later invoked to destroy the servant created by the
      preinvoke operation. 
    </P>
    <PRE>
      #include "tao/corba.h"
      
      class Quoter_Stock_Factory_Locator_i : public POA_PortableServer::ServantLocator
      {
       public:
        Quoter_Stock_Factory_Locator_i (CORBA::ORB_ptr orb);
    
        // Preinvoke function
        virtual PortableServer::Servant preinvoke (const PortableServer::ObjectId &oid, 
                                                   PortableServer::POA_ptr poa, 
                                                   const char * operation, 
                                                   void * & cookie)
          throw (CORBA::SystemException, PortableServer::ForwardRequest);
  
        // Postinvoke function
        virtual void postinvoke (const PortableServer::ObjectId & oid, 
                                 PortableServer::POA_ptr poa,
                                 const char * operation, 
                                 void * cookie, 
                                 PortableServer::Servant servant)
          throw (CORBA::SystemException);

       private:
        CORBA::ORB_var orb_;
      };
    </PRE>
    <P>In the implementation of the <CODE>preinvoke</CODE> operation, we check if
      the object ID is valid and then check for the servant we want to
      create and create and return the requested servant.
    <PRE>
    <PRE>
     PortableServer::Servant
     Quoter_Stock_Factory_Locator_i::preinvoke (const PortableServer::ObjectId &oid, 
                                                 PortableServer::POA_ptr poa, 
                                                 const char * operation, 
                                                 void * & cookie)
       throw (CORBA::SystemException, PortableServer::ForwardRequest)
     {

       try {
  
        // Get the ObjectID in string format
        CORBA::String_var oid_str = 
          PortableServer::ObjectId_to_string (oid);

        // Check if the ObjectId is valid
        if (strcmp (oid_str.in (), "Quoter/Stock_Factory") != 0) {
          // Create the requested servant.
          PortableServer::Servant servant = 
            new Quoter_Stock_Factory_i ();
        
         cookie = servant;

         return servant;
        }
        else {
          throw CORBA::OBJECT_NOT_EXIST ();
        }

      }catch (const CORBA::BAD_PARAM &) {
        throw CORBA::OBJECT_NOT_EXIST ();
      }
    </PRE>
    <P>The implementation of the <CODE>postinvoke</CODE> operation is
      simple. We just destroy the servant which we created by the
      <CODE>preinvoke</CODE> operation. The <CODE>Cookie IDL
      type</CODE> which is a parameter in both these operations
      helps associate the invocation of <CODE>preinvoke</CODE> with
      its <CODE>postinvoke</CODE> operation. 
    </P>
    <PRE>
      void 
      Quoter_Stock_Factory_Locator_i::postinvoke (const PortableServer::ObjectId &oid, 
                                                  PortableServer::POA_ptr poa, 
                                                  const char * operation, 
                                                  void * cookie, 
                                                  PortableServer::Servant servant)
        throw (CORBA::SystemException)
      {
  
        // Delete the servant as it is no longer needed.
        PortableServer::Servant my_servant = (PortableServer::Servant) cookie;
        if (servant == my_servant)
          delete servant;
      }
    </PRE>
    <H3> Server Implementation </H3>
    <P>Our first steps would be to create a new POA from the RootPOA
      with the <CODE>USE_SERVANT_MANAGER</CODE> value for the 
      <CODE>RequestProcessingPolicy</CODE> and <CODE>NON_RETAIN</CODE>
      for the <CODE>ServantRetentionPolicy</CODE>.
    </P>
    <PRE>
        CORBA::PolicyList policies (3);
        policies.length (3);

        // Assign the polices
        policies [0] =
          poa->create_id_assignment_policy (PortableServer::USER_ID);

        policies [1] = 
          poa->create_request_processing_policy 
                                (PortableServer::USE_SERVANT_MANAGER);

        policies [2] = 
          poa->create_servant_retention_policy (PortableServer::NON_RETAIN);

        // Create the POA with these policies
        PortableServer::POA_var child_poa = 
          poa->create_POA ("childPOA", 
                           poa_manager.in (), 
                           policies);

        // Destroy the policy objects
        for (CORBA::ULong i = 0; i != policies.length (); ++i) {
          policies[i]->destroy ();
        }

    </PRE>
    <P> The policy values are assigned, the <CODE>childPOA</CODE> is
      created with these policies, and later these policy objects can be
      deleted, as a copy of these objects is made by the
      <CODE>create_POA</CODE> and we would not need these objects any more.
    </P>
    <P> Now that we have the POA which can support servant managers,
      the next step would be to create a servant for the servant
      locator object, activate it to obtain its reference, and set it as
      the servant manager with the childPOA.
    </P>
    <PRE>
       // Create a Stock_Factory_Locator servant
       Quoter_Stock_Factory_Locator_i servant_locator_i(orb.in ());
   
       // Need to activate a servant_manager object in the Root POA
       PortableServer::ServantLocator_var servant_locator = 
         servant_locator_i._this ();
    
       // Set the SM with the childPOA
       child_poa->set_servant_manager (servant_locator.in ());
    </PRE>
    <P>Now that we have set the servant manager with the childPOA, the
      next step would be to create a reference with the user-created
      ID in the childPOA which uses the Quoter_Stock_Factory_Locator_i.
      The <CODE>create_reference_with_id</CODE> operation lets us
      create the required object without actually creating its servant.
      The application supplies the ObjectId which signifies the 
      identity of the object in the application domain.
    </P>
    <PRE>
       // Get the Object Id
       PortableServer::ObjectId_var child_oid = 
         PortableServer::string_to_ObjectId ("childFoo");

       //Create the Object without creating the servants
       CORBA::Object_var stock_factory = 
         child_poa->create_reference_with_id (child_oid.in (), 
                                              "IDL:Quoter/Stock_Factory:1.0");
    </PRE>
    <P>After this, as before, let's put this object reference as an IOR
      string and print it out. 
    </P>
    <PRE>
       // Put the object reference as an IOR string
       CORBA::String_var ior = orb->object_to_string (stock_factory.in ());
       
       // Print it out!
       std::cout << ior.in () << std::endl;
    </PRE>
    <H3>Excercise</H3>
    <P>Modify the <a href="../Simple/Server/server.cpp">server.cpp</a> in 
      the simple server to use servant managers and locators. Use
      these files to help complete the implementation.
      <a href="Stock_Factory_Locator_i.h">Stock_Factory_locator_i.h</a>
      <a href="Stock_Factory_Locator_i.cpp">Stock_Factory_locator_i.cpp</a> 
      <a href="Makefile">Makefile</a>.
    </P>
    <H3>Solution</H3>
    <P>Look at the <a href="server.cpp">server.cpp</a> file. It should not
	be much different from yours.
    </P>
    <H3>Testing</H3>
    <P>A client which uses request handlers is provided:
      <a href="../AMI/client.cpp">client.cpp</a>. As before the
      following files are provided.
      <a href="../AMI/Quoter.idl">Quoter.idl</a>
      <a href="../On_Demand_Activation/Stock_i.h">Stock_i.h</a>
      <a href="../On_Demand_Activation/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="../AMI/Handler_i.h">Handler_i.h</a> and
      <a href="../AMI/Handler_i.cpp">Handler_i.cpp</a>.
    </P>
    <H3>More Reading</H3>
    <P>The 
    <P>The <A HREF="http://www.triodia.com/staff/michi-henning.html">Henning</A> and
      <A HREF="http://www.iona.com/hyplan/vinoski/">Vinoski</A> 
      <A HREF="http://www.iona.com/hyplan/vinoski/#book">CORBA book</A> 
      discusses POA policies in detail.  Likewise, the Schmidt and Vinoski 
      <A HREF="http://www.cs.wustl.edu/~schmidt/report-doc.html">columns </A>
      in C++ Report also include several articles about the POA.  Finally,
      the <A HREF="http://www.cs.wustl.edu/~schmidt/TAO.html">TAO</a>
      distribution includes 
      <A HREF="../../../../examples/POA">examples</A> that illustrate how to use the POA policies.
    </P>
    <hr>
    <address><a href="mailto:pgontla@ece.uci.edu">Priyanka Gontla</a></address>
    <!-- Created: Mon May  1 11:08:56 PDT 2000 -->
    <!-- hhmts start -->
Last modified: Tue Apr 24 17:50:17 CDT 2001
<!-- hhmts end -->
  </body>
</html>