source: trunk/third/bonobo/bonobo/bonobo-transient.c @ 16750

Revision 16750, 16.7 KB checked in by ghudson, 23 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r16749, which included commits to RCS files with non-trunk default branches.
Line 
1/**
2 * Bonobo transient object implementation.
3 *
4 * This simplifies the creation of POA managers for transient objects.
5 * Objects living in this POA are created on demand and destroyed after use.
6 *
7 * Authors:
8 *   Nat Friedman    (nat@helixcode.com)
9 *   Miguel de Icaza (miguel@helixcode.com)
10 *
11 * I just refactored the code from the original PropertyBag, all the smart hacks
12 * are from Nat -mig.
13 *
14 * (C) 2000 Helix Code, Inc.
15 */
16#include <config.h>
17#include <bonobo/Bonobo.h>
18#include <bonobo/bonobo-main.h>
19#include <bonobo/bonobo-exception.h>
20#include <bonobo/bonobo-transient.h>
21
22static GtkObjectClass *parent_class = NULL;
23
24/*
25 * BonoboTransient POA and Servant Manager.
26 */
27typedef struct {
28        POA_PortableServer_ServantLocator servant_locator;
29        BonoboTransient *bonobo_transient;
30} BonoboTransientServantManager;
31
32struct _BonoboTransientPriv {
33        BonoboTransientServantNew     new_servant;
34        BonoboTransientServantDestroy destroy_servant;
35        gpointer                      callback_data;
36        PortableServer_POA            poa;     
37};
38
39/*
40 * This ServantManager method is invoked before a method
41 * on a BonoboTransient is called.  It creates the servant
42 * for the object and returns it.
43 */
44static PortableServer_Servant
45bonobo_transient_servant_locator_preinvoke (PortableServer_Servant servant_manager,
46                                            PortableServer_ObjectId *oid,
47                                            PortableServer_POA adapter,
48                                            CORBA_Identifier op_name,
49                                            PortableServer_ServantLocator_Cookie *cookie,
50                                            CORBA_Environment *ev)
51{
52        BonoboTransientServantManager *sm;
53        PortableServer_Servant servant = NULL;
54        BonoboTransient *transient, **cookie_val;
55        char *object_name;
56
57        /*
58         * Get the TransientManager out of the servant manager.
59         */
60        sm = (BonoboTransientServantManager *) servant_manager;
61        transient = sm->bonobo_transient;
62
63        /*
64         * Grab the Property name and the Property Bag.
65         */
66        object_name = PortableServer_ObjectId_to_string (oid, ev);
67        if (BONOBO_EX (ev)) {
68                CORBA_free (object_name);
69                g_warning ("BonoboPropertyBag: Could not get property name from Object ID");
70                return NULL;
71        }
72
73        /*
74         * Create a temporary servant
75         */
76        servant = transient->priv->new_servant (
77                adapter, transient, object_name, transient->priv->callback_data);
78        CORBA_free (object_name);
79        if (servant == NULL) {
80                g_warning ("BonoboPropertyBag: Could not create transient Property servant");
81                CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO);
82                return NULL;
83        }
84
85        /*
86         * The cookie is arbitrary data which will get passed to
87         * postinvoke for this Property method invocation.  We have no
88         * use for it.
89         */
90        cookie_val = g_new (BonoboTransient *, 1);
91        *cookie_val = transient;
92        *cookie = cookie_val;
93
94        return servant;
95}
96
97/*
98 * This method is invoked after a BonoboProperty method invocation.
99 * It destroys the transient Property servant.
100 */
101static void
102bonobo_transient_servant_locator_postinvoke (PortableServer_Servant servant_manager,
103                                             PortableServer_ObjectId *oid,
104                                             PortableServer_POA adapter,
105                                             CORBA_Identifier op_name,
106                                             PortableServer_ServantLocator_Cookie cookie,
107                                             PortableServer_Servant servant,
108                                             CORBA_Environment *ev)
109{
110        BonoboTransient *transient =
111                BONOBO_TRANSIENT (*((BonoboTransient **)cookie));
112       
113        transient->priv->destroy_servant (servant, transient->priv->callback_data);
114
115        g_free (cookie);
116}
117
118static PortableServer_ServantBase__epv *
119bonobo_transient_get_servant_base_epv (void)
120{
121        PortableServer_ServantBase__epv *epv;
122
123        epv = g_new0 (PortableServer_ServantBase__epv, 1);
124
125        epv->default_POA = PortableServer_ServantBase__default_POA;
126        epv->finalize    = PortableServer_ServantBase__fini;
127
128        return epv;
129}
130
131
132static POA_PortableServer_ServantManager__epv *
133bonobo_transient_get_servant_manager_epv (void)
134{
135        POA_PortableServer_ServantManager__epv *epv;
136
137        epv = g_new0 (POA_PortableServer_ServantManager__epv, 1);
138
139        return epv;
140}
141
142static POA_PortableServer_ServantLocator__epv *
143bonobo_transient_get_servant_locator_epv (void)
144{
145        POA_PortableServer_ServantLocator__epv *epv;
146
147        epv = g_new0 (POA_PortableServer_ServantLocator__epv, 1);
148
149        epv->preinvoke  = bonobo_transient_servant_locator_preinvoke;
150        epv->postinvoke = bonobo_transient_servant_locator_postinvoke;
151
152        return epv;
153}
154
155static POA_PortableServer_ServantLocator__vepv *
156bonobo_transient_get_servant_locator_vepv (void)
157{
158        static POA_PortableServer_ServantLocator__vepv *vepv = NULL;
159
160        if (vepv != NULL)
161                return vepv;
162
163        vepv = g_new0 (POA_PortableServer_ServantLocator__vepv, 1);
164
165        vepv->_base_epv                         = bonobo_transient_get_servant_base_epv ();
166        vepv->PortableServer_ServantManager_epv = bonobo_transient_get_servant_manager_epv ();
167        vepv->PortableServer_ServantLocator_epv = bonobo_transient_get_servant_locator_epv ();
168
169        return vepv;
170}
171
172/**
173 * bonobo_transient_construct:
174 * @transient: the BonoboTransient to construct
175 * @parent_poa: the POA where the object is created, CORBA_OBJECT_NIL for the default Bonobo POA.
176 * @new_servant: A function pointer used to incarnate servants on demand.
177 * @destroy_servant: A function pointer used to destroy the on-demand server.
178 * @data: data passed to the @new_servant and @destroy_servant functions.
179 *
180 * This function is only for wrappers and object derivation.  For normal
181 * use, please see #bonobo_transient_new.
182 *
183 * This function will return %NULL on failure; however it is your
184 * responsibility to destroy the failed object in that case.
185 *
186 * Returns: a #BonoboTransient object (the @transient)
187 */
188BonoboTransient *
189bonobo_transient_construct (BonoboTransient          *transient,
190                            PortableServer_POA        poa,
191                            BonoboTransientServantNew new_servant,
192                            BonoboTransientServantDestroy destroy_servant,
193                            gpointer data)
194{
195        CORBA_PolicyList                *policies;
196        BonoboTransientServantManager   *sm;
197        CORBA_Environment                ev;
198        char                            *poa_name;
199        gboolean                         success;
200
201        success = FALSE;
202
203        transient->priv->new_servant = new_servant;
204        transient->priv->destroy_servant = destroy_servant;
205        transient->priv->callback_data = data;
206
207        if (poa == CORBA_OBJECT_NIL)
208                poa = bonobo_poa ();
209       
210        transient->priv->poa = poa;
211       
212        CORBA_exception_init (&ev);
213       
214        /*
215         * Create a new custom POA which will manage the
216         * BonoboTransient objects.  We need a custom POA because there
217         * may be many, many properties and we want to avoid
218         * instantiating a servant for each one of them from the
219         * outset (which is what the default POA will require).
220         *
221         * Our new POA will have a special Policy set --
222         * USE_SERVANT_MANAGER -- which means that, when a request
223         * comes in for one of the objects (properties) managed by
224         * this POA, the ORB will dispatch to our special
225         * ServantManager.  The ServantManager will then incarnate the
226         * Servant for the Property which is being operated on.  So we
227         * are creating a ServantManager which will incarnate Property
228         * servants as-needed, and a POA which knows how to dispatch
229         * to our special ServantManager.
230         *
231         * Repetition is probably the only way to get this across, so
232         * allow me to rephrase: When a request comes in for a particular
233         * object, the POA uses the servant manager to get the servant
234         * for the specified object reference.
235         *
236         * This is just on-demand object creation, mired in a bunch of
237         * CORBA jargon.
238         *
239         * The take home message: Each Bonobo Property CORBA object is
240         * not created until someone actually invokes one of its
241         * methods.
242         */
243       
244        /*
245         * Create a list of CORBA policies which we will apply to our
246         * new POA.
247         */
248        policies = g_new0 (CORBA_PolicyList, 1);
249        policies->_maximum = 4;
250        policies->_length  = 4;
251        policies->_buffer  = g_new0 (CORBA_Policy,
252                                     policies->_length);
253        policies->_release = CORBA_FALSE;
254       
255        /*
256         * Create a new CORBA Policy object which specifies that we
257         * will be using a ServantManager, thank you very much.
258         */
259        policies->_buffer [0] = (CORBA_Policy)
260                PortableServer_POA_create_request_processing_policy (
261                        bonobo_poa (),                       /* This argument is ignored. */
262                        PortableServer_USE_SERVANT_MANAGER,
263                        &ev);
264       
265        if (BONOBO_EX (&ev)) {
266                g_warning ("Could not create request processing policy for BonoboTransient POA");
267                CORBA_exception_free (&ev);
268                goto out;
269        }
270       
271        /*
272         * Now, to add a touch more complexity to the whole
273         * system, we go further than just creating Property
274         * servants on-demand; we make them completely transient.
275         * What this means is that, when a Property servant has
276         * finished processing a request on the property object,
277         * it disappears.  So we only use resources on property
278         * servants while a property method invocation is being
279         * processed.  (Now I'm just showing off)
280         *
281         * This is actually important because, with Controls,
282         * properties are used to manipulate many highly-variant
283         * run-time attributes (not just crap like font size).  The
284         * Microsoft ActiveX web controls, for example, use properties
285         * to allow the user (the parent application) to get/set the
286         * current URL being displayed.
287         *
288         * Accordingly, the following CORBA Policy specifies that
289         * servants should not be retained.
290         */
291        policies->_buffer [1] = (CORBA_Policy)
292                PortableServer_POA_create_servant_retention_policy (
293                        bonobo_poa (),
294                        PortableServer_NON_RETAIN,
295                        &ev);
296       
297        if (BONOBO_EX (&ev)) {
298                g_warning ("Could not create servant retention policy for BonoboTransient POA '%s'",
299                           bonobo_exception_get_text (&ev));
300                CORBA_exception_free (&ev);
301                goto out;
302        }
303       
304        /*
305         * Set the threading model to SINGLE_THREAD_MODEL, otherwise
306         * an ORB could use the default ORB_CTRL_MODEL, which is to
307         * let the ORB make threads for requests as it likes.
308         */
309        policies->_buffer [2] = (CORBA_Policy)
310                PortableServer_POA_create_thread_policy (
311                        bonobo_poa (),
312                        PortableServer_SINGLE_THREAD_MODEL,
313                        &ev);
314       
315        if (BONOBO_EX (&ev)){
316                g_warning ("Could not create threading policy for BonoboTransient POA '%s'",
317                           bonobo_exception_get_text (&ev));
318                CORBA_exception_free (&ev);
319                goto out;
320        }
321
322        policies->_buffer [3] = (CORBA_Policy)
323                PortableServer_POA_create_implicit_activation_policy (
324                        bonobo_poa (),
325                        PortableServer_NO_IMPLICIT_ACTIVATION,
326                        &ev);
327
328        if (BONOBO_EX (&ev)){
329                g_warning ("Could not create activation policy for BonoboTransient POA '%s'",
330                           bonobo_exception_get_text (&ev));
331                CORBA_exception_free (&ev);
332                goto out;
333        }
334
335        /*
336         * Create the BonoboProperty POA as a child of the root
337         * Bonobo POA.
338         */
339        poa_name = g_strdup_printf ("BonoboTransient %p", transient);
340        transient->priv->poa = PortableServer_POA_create_POA (
341                bonobo_poa (), poa_name, bonobo_poa_manager (),
342                policies, &ev);
343        g_free (poa_name);
344
345        if (BONOBO_EX (&ev)) {
346                g_warning ("BonoboTransient: Could not create BonoboTransient POA '%s'",
347                           bonobo_exception_get_text (&ev));
348                CORBA_exception_free (&ev);
349                goto out;
350        }
351       
352        /*
353         * Create our ServantManager.
354         */
355        sm = g_new0 (BonoboTransientServantManager, 1);
356        sm->bonobo_transient = transient;
357
358        ((POA_PortableServer_ServantLocator *) sm)->vepv = bonobo_transient_get_servant_locator_vepv ();
359               
360        POA_PortableServer_ServantLocator__init (((PortableServer_ServantLocator *) sm), &ev);
361        if (BONOBO_EX (&ev)) {
362                g_warning ("BonoboTransient: Could not initialize ServantLocator");
363                CORBA_exception_free (&ev);
364                g_free (sm);
365                goto out;
366        }
367
368        PortableServer_POA_set_servant_manager (
369                transient->priv->poa,
370                (PortableServer_ServantManager) sm, &ev);
371
372        if (BONOBO_EX (&ev)) {
373                g_warning ("BonoboTransient: Could not set POA servant manager");
374                CORBA_exception_free (&ev);
375                g_free (sm);
376                goto out;
377        }
378
379        success = TRUE;
380
381 out:
382        if (policies->_buffer [0] != NULL) {
383                CORBA_Policy_destroy (policies->_buffer [0], &ev);
384
385                if (BONOBO_EX (&ev)) {
386                        g_warning ("bonobo_transient_construct(): could not destroy the "
387                                   "request processing policy");
388                        CORBA_exception_free (&ev);
389                        success = FALSE;
390                }
391        }
392
393        if (policies->_buffer [1] != NULL) {
394                CORBA_Policy_destroy (policies->_buffer [1], &ev);
395
396                if (BONOBO_EX (&ev)) {
397                        g_warning ("bonobo_transient_construct(): could not destroy the "
398                                   "servant retention policy");
399                        CORBA_exception_free (&ev);
400                        success = FALSE;
401                }
402        }
403
404        if (policies->_buffer [2] != NULL) {
405                CORBA_Policy_destroy (policies->_buffer [2], &ev);
406
407                if (BONOBO_EX (&ev)) {
408                        g_warning ("bonobo_transient_construct(): could not destroy the "
409                                   "threading policy");
410                        CORBA_exception_free (&ev);
411                        success = FALSE;
412                }
413        }
414
415        if (policies->_buffer [3] != NULL) {
416                CORBA_Policy_destroy (policies->_buffer [3], &ev);
417
418                if (BONOBO_EX (&ev)) {
419                        g_warning ("bonobo_transient_construct(): could not destroy the "
420                                   "activation policy");
421                        CORBA_exception_free (&ev);
422                        success = FALSE;
423                }
424        }
425
426        g_free (policies->_buffer);
427        g_free (policies);
428
429        if (success)
430                return transient;
431        else
432                return NULL;
433}
434
435static void
436bonobo_transient_destroy (GtkObject *object)
437{
438        BonoboTransient *transient = BONOBO_TRANSIENT (object);
439       
440        if (transient->priv->poa) {
441                CORBA_Environment ev;
442
443                /* Destroy the POA. */
444                CORBA_exception_init (&ev);
445                PortableServer_POA_destroy (transient->priv->poa, FALSE, TRUE, &ev);
446
447                if (BONOBO_EX (&ev))
448                        g_warning ("bonobo_transient_destroy: Could not destroy POA.");
449
450                CORBA_exception_free (&ev);
451        } else
452                g_warning ("No poa to destroy");
453
454        g_free (transient->priv);
455       
456        parent_class->destroy (object);
457}
458
459static void
460bonobo_transient_class_init (BonoboTransientClass *class)
461{
462        GtkObjectClass *object_class = (GtkObjectClass *) class;
463
464        parent_class = gtk_type_class (gtk_object_get_type ());
465
466        object_class->destroy = bonobo_transient_destroy;
467}
468
469static void
470bonobo_transient_init (BonoboTransient *transient)
471{
472        transient->priv = g_new0 (BonoboTransientPriv, 1);
473}
474
475/**
476 * bonobo_transient_get_type:
477 *
478 * Returns: The GtkType corresponding to the BonoboTransient class.
479 */
480GtkType
481bonobo_transient_get_type (void)
482{
483        static GtkType type = 0;
484
485        if (! type) {
486                GtkTypeInfo info = {
487                        "BonoboTransient",
488                        sizeof (BonoboTransient),
489                        sizeof (BonoboTransientClass),
490                        (GtkClassInitFunc) bonobo_transient_class_init,
491                        (GtkObjectInitFunc) bonobo_transient_init,
492                        NULL, /* reserved 1 */
493                        NULL, /* reserved 2 */
494                        (GtkClassInitFunc) NULL
495                };
496
497                type = gtk_type_unique (gtk_object_get_type (), &info);
498        }
499
500        return type;
501}
502
503/**
504 * bonobo_transient_new:
505 * @parent_poa: the POA where the object is created, CORBA_OBJECT_NIL for the default Bonobo POA.
506 * @new_servant: A function pointer used to incarnate servants on demand.
507 * @destroy_servant: A function pointer used to destroy the on-demand server.
508 * @data: data passed to the @new_servant and @destroy_servant functions.
509 *
510 * bonobo_transient_new() creates a new CORBA server that creates a
511 * new POA entry (within the @parent_poa POA).  You can construct
512 * arbitrary object names inside this space using
513 * bonobo_transient_create_objref() and return those to
514 * client code.
515 *
516 * The @new_servant function will be invoked by the POA to resolve
517 * object reference to names you have created using
518 * bonobo_transient_create_objref().  The @new_servant function
519 * should return a PortableServer_Servant that will handle the request.
520 *
521 * Once the processing is completed, the @destroy_servant will be invoked
522 * to release any resources allocated during the invocation of @new_servant
523 * or during the execution of the servant that need to be released.
524 *
525 * Returns: a new BonoboTransient object.
526 */
527BonoboTransient *
528bonobo_transient_new (PortableServer_POA poa,
529                      BonoboTransientServantNew new_servant,
530                      BonoboTransientServantDestroy destroy_servant,
531                      gpointer data)
532{
533        BonoboTransient *transient;
534
535        transient = gtk_type_new (BONOBO_TRANSIENT_TYPE);
536        if (bonobo_transient_construct (transient, poa, new_servant, destroy_servant, data) == NULL) {
537                gtk_object_destroy (GTK_OBJECT (transient));
538                return NULL;
539        }
540
541        return transient;
542}
543
544/**
545 * bonobo_transient_create_objref:
546 * @transient: The BonoboTransient manager where the object reference is rooted.
547 * @iface_name: The CORBA interface name that the returned object is supposed to implement.
548 * @name: The name of the object inside the @transient POA's name space.
549 * @ev: returns possible errors from the PortableServer_POA_create_reference_with_id() call.
550 *
551 * Returns: a CORBA_Object reference for an object named @name inside
552 * the @transient's POA naming space that implements the @iface_name interface
553 *
554 * The return value can be CORBA_OBJECT_NIL to indicate an error in the
555 * incoming arguments.
556 */
557CORBA_Object
558bonobo_transient_create_objref (BonoboTransient   *transient,
559                                const char        *iface_name,
560                                const char        *name,
561                                CORBA_Environment *ev)
562{
563        PortableServer_ObjectId *oid;
564
565        g_return_val_if_fail (transient != NULL, CORBA_OBJECT_NIL);
566        g_return_val_if_fail (BONOBO_IS_TRANSIENT (transient), CORBA_OBJECT_NIL);
567        g_return_val_if_fail (name != NULL, CORBA_OBJECT_NIL);
568        g_return_val_if_fail (ev != NULL, CORBA_OBJECT_NIL);
569
570        oid = PortableServer_string_to_ObjectId ((char *) name, ev);
571        if (oid == NULL)
572                return CORBA_OBJECT_NIL;
573
574        return (CORBA_Object) PortableServer_POA_create_reference_with_id (
575                transient->priv->poa, oid, (char *) iface_name, ev);
576}
577
Note: See TracBrowser for help on using the repository browser.