Previous Up Next

Chapter 5  Creation of POA Hierarchies Made Simple

The CORBA POA specification is considered by many to be powerful but complex. Actually, the POA specification is powerful and conceptually simple. Unfortunately, verbose APIs obscure the simple concepts that are at the heart of the POA specification. It is these verbose APIs that are largely to blame for the reputation that the POA specification has for being complex.

This chapter discusses a class called PoaUtility that provides a simplification “wrapper” around the POA APIs. The wrapper API contains just three operations that provide all the power and flexibility previously provided by a dozen operations of the “raw” POA API. The PoaUtility class does not hide the concepts of the POA. In fact, it is just the opposite: by replacing a dozen low-level operations with a smaller number of higher-level operations, the wrapper allows developers to more easily see the underlying simplicity and elegance of the POA.

Currently, the PoaUtility class works “out of the box” with five CORBA products: Orbix/C++, Orbix/Java, Orbacus/C++, Orbacus/Java, and TAO. It should be easy to extend support to other CORBA products and/or languages.

5.1  Introduction

Many people have mixed feelings about the POA specification. On the one hand, it provides CORBA with a lot of power and flexibility. On the other hand, the POA specification can seem complex, and this puts a lot of developers off CORBA. This is a shame because the POA specification is conceptually simple and is actually quite elegant. It is just that verbose APIs obscure the simple concepts that are at the heart of the POA specification.

This chapter discusses a class called PoaUtility that provides a simplification “wrapper” around the POA APIs. The wrapper API contains just three operations that provide all the power and flexibility previously provided by a dozen operations of the “raw” POA API. The PoaUtility class does not hide the concepts of the POA. In fact, it is just the opposite: by replacing a dozen low-level operations with a smaller number of higher-level operations, the wrapper allows developers to more easily see the underlying simplicity and elegance of the POA.

Some important benefits of the wrapper API are as follows:

Currently, the PoaUtility class works “out of the box” with six CORBA products: Orbix/C++, Orbix/Java, Orbacus/C++, Orbacus/Java, TAO and omniORB. It should be easy to extend support to other CORBA products and/or languages. Section 5.5 offers some advice for readers who are interested in porting the PoaUtility class to other CORBA products.

5.2  Building A POA Hierarchy

We introduce the PoaUtility class by showing how it is typically used to construct a POA hierarchy. Let us assume that you are writing a CORBA server with the following characteristics:

The above functionality can be implemented by a class called, say, PoaHierarchy that makes use of the functionality provided by the PoaUtility class. A C++ implementation of this class is presented in Section 5.2.1, and a Java version is presented in Section 5.2.2.

5.2.1  C++ Version

The declaration of the C++ PoaHierarchy class is shown below.

 1 #include "PoaUtility.h"
 2 using namespace corbautil;
 3 class PoaHierarchy : PoaUtility
 4 {
 5 public:
 6   PoaHierarchy(CORBA::ORB_ptr               orb,
 7                PoaUtility::DeploymentModel  deployModel)
 8                                   throw(PoaUtilityException)
 9   //——–
10   // Accessors
11   //——–
12   POAManager_ptr   core_functionality()
13                          { return m_core_functionality.mgr(); }
14   POAManager_ptr   admin_functionality()
15                          { return m_admin_functionality.mgr(); }
16   POA_ptr          FooFactory()     { return m_FooFactory; }
17   POA_ptr          Foo()            { return m_Foo; }
18   POA_ptr          Administration() { return m_Administration; }
19
20 private:
21   //——–
22   // Instance variables
23   //——–
24   LabelledPOAManager    m_core_functionality;
25   LabelledPOAManager    m_admin_functionality;
26   POA_var               m_FooFactory;
27   POA_var               m_Foo;
28   POA_var               m_Administration;
29
30   //——–
31   // The following are not implemented
32   //——–
33   PoaHierarchy();
34   PoaHierarchy(const PoaHierarchy &);
35   PoaHierarchy & operator=(const PoaHierarchy &);
36 };

The following points should be noted:

All the interesting functionality of the PoaHierarchy class is implemented in its constructor, which is shown below. Comments follow after the code.

 1 #include "PoaHierarchy.h"
 2
 3 PoaHierarchy::PoaHierarchy(CORBA::ORB_ptr              orb,
 4                            PoaUtility::DeploymentModel deployModel)
 5                                       throw(PoaUtilityException)
 6   : PoaUtility(orb, deployModel)
 7 {
 8   //——–
 9   // Create the POA Managers
10   //——–
11   m_core_functionality =
12                    createPoaManager("core_functionality");
13   m_admin_functionality =
14                    createPoaManager("admin_functionality");
15
16   //——–
17   // Create the FooFactory POA
18   //——–
19   m_FooFactory = createPoa("FooFactory",
20             root(), m_core_functionality,
21             "user_id + persistent + use_active_object_map_only");
22
23   //——–
24   // Create the FooFactory/Foo POA
25   //——–
26   m_Foo = createPoa("Foo",
27             m_FooFactory, m_core_functionality,
28             "system_id + transient + unique_id + retain"
29             "+ use_active_object_map_only");
30
31   //——–
32   // Create the Administration POA
33   //——–
34   m_Administration = createPoa("Administration",
35             root(), m_admin_functionality,
36             "single_thread_model + persistent + user_id"
37             "+ use_active_object_map_only");
38 }

The following points should be noted:

5.2.1.1  Using the POA Hierarchy in a Server Application

The code below illustrates the mainline of a server that uses the PoaHierarchy class. Comments follow after the code.

 1 CORBA::ORB_var            g_orb;
 2 PoaHierarchy *            g_poa_h;
 3 FooFactory_impl *         g_FooFactory_sv;
 4 Administration_impl *     g_Administration_sv;
 5
 6 int main(int argc, char ** argv)
 7 {
 8     PortableServer::ObjectId_var    obj_id;
 9
10     int exitStatus = 0;
11     try {
12         //——–
13         // Initialize CORBA and create the POA hierarchy
14         //——–
15         g_orb = CORBA::ORB_init(argc, argv);
16         PoaUtility::DeploymentModel deployModel = ...;
17         g_poa_h = new PoaHierarchy(g_orb, deployModel);
18
19         //——–
20         // Create and activate singleton servants
21         //——–
22         g_FooFactory_sv = new FooFactory_impl();
23         obj_id = ...;
24         g_poa_h->FooFactory()->activate_object_with_id(
25                                  obj_id, g_FooFactory_sv);
26         g_FooFactory_sv->_remove_ref();
27         ... // similar code for the Administration singleton
28
29         //——–
30         // Export singleton object references
31         //——–
32         ...
33
34         //——–
35         // Activate POA managers and go into the event loop
36         //——–
37         g_poa_h->core_functionality()->activate();
38         g_poa_h->admin_functionality()->activate();
39         g_orb->run();
40     }
41     catch (const CORBA::Exception & ex) {
42         cout << ex << endl;
43         exitStatus = 1;
44     }
45     catch (corbautil::PoaUtilityException & ex) {
46         cout << ex << endl;
47         exitStatus = 1;
48     }
49
50     //——–
51     // Tidy up and terminate
52     //——–
53     delete g_poa_h;
54     if (!CORBA::is_nil(g_orb)) {
55         try {
56             g_orb->destroy();
57         } catch (const CORBA::Exception & ex) {
58             cout << "orb->destroy() failed: " << ex << endl;
59             exitStatus = 1;
60         }
61     }
62     return exitStatus;
63 }

The following points should be noted:

5.2.2  Java Version

The Java version of the PoaHierarchy class is shown below.

 1 import org.omg.CORBA.*;
 2 import org.omg.PortableServer.*;
 3 import com.iona.corbautil.*;
 4 class PoaHierarchy
 5 {
 6    public PoaHierarchy(ORB orb, int deployModel)
 7                 throws PoaUtilityException
 8    {
 9         PoaUtility util = PoaUtility.init(orb, deployModel);
10         m_core_functionality  = util.createPoaManager(
11                                        "core_functionality");
12         m_admin_functionality = util.createPoaManager(
13                                        "admin_functionality");
14
15         m_FooFactory =  util.createPoa("FooFactory",
16                                  util.root(),
17                                  m_core_functionality,
18                                  "user_id + persistent +"
19                                  + "use_active_object_map_only");
20
21         m_Foo =  util.createPoa("Foo", m_FooFactory,
22                                  m_core_functionality,
23                                  "system_id + transient +"
24                                  + "unique_id + retain +"
25                                  + "use_active_object_map_only");
26
27         m_Administration =  util.createPoa("Administration",
28                                  util.root(),
29                                  m_admin_functionality,
30                                  "single_thread_model +"
31                                  + "persistent + user_id +"
32                                  + "use_active_object_map_only");
33     }
34
35    //——–
36    // Accessors
37    //——–
38    public POA FooFactory()       { return m_FooFactory; }
39    public POA Foo()              { return m_Foo; }
40    public POA Administration()   { return m_Administration; }
41    public POAManager core_functionality()
42                          { return m_core_functionality.mgr(); }
43    public POAManager admin_functionality()
44                          { return m_admin_functionality.mgr(); }
45
46     //——–
47     // Instance variables
48     //——–
49     private LabelledPOAManager    m_core_functionality;
50     private LabelledPOAManager    m_admin_functionality;
51     private POA                   m_FooFactory;
52     private POA                   m_Foo;
53     private POA                   m_Administration;
54 }

The following points should be noted:

5.2.2.1  Using the POA Hierarchy in a Server Application

The code below illustrates the mainline of a server that uses the PoaHierarchy class. Comments follow after the code.

 1 import org.omg.CORBA.*;
 2 import org.omg.PortableServer.*;
 3
 4 public class Server
 5 {
 6     public static ORB                   orb;
 7     public static PoaHierarchy          poaH;
 8     public static FooFactoryImpl        fooFactorySv;
 9     public static AdministrationImpl    administrationSv;
10
11     public static void main(String args[])
12     {
13         try {
14             //——–
15             // Initialize the ORB and create the POA Hierarchy
16             //——–
17             orb = ORB.init(args, null);
18             int deployModel = ...;
19             poaH  = new PoaHierarchy(orb, deployModel);
20
21             //——–
22             // Create and activate singleton servants
23             //——–
24             fooFactorySv = new FooFactoryImpl();
25             poaH.FooFactory().activate_object_with_id(
26                        "FooFactory".getBytes(), fooFactorySv);
27             ... // similar code for the Administration singleton
28
29             //——–
30             // Export singleton object references
31             //——–
32             ...
33
34             //——–
35             // Activate POA Managers and go into the event loop
36             //——–
37             poaH.core_functionality().activate();
38             poaH.admin_functionality().activate();
39             orb.run();
40
41         } catch (PoaUtilityException ex) {
42             System.out.println(ex.getMessage());
43         } catch (Exception ex) {
44             System.out.println(ex.toString());
45         }
46 
47         //——–
48         // Tidy up and terminate
49         //——–
50         if (orb != null) {
51             try {
52                 orb.destroy();
53             } catch (Exception e) {
54             }
55         }
56     }
57 }

The following points should be noted:

5.3  Server Deployment Models

The CORBA specification describes an implementation repository. This term is not very intuitive so it deserves an explanation. Implementation is the CORBA terminology for “server application”, and repository means a persistent storage area, such as a database. Thus, implementation repository (commonly abbreviated to IMR) is a database that stores information about CORBA server applications. Most of the functionality of an IMR must be implemented in a platform-specific manner. For this reason, the CORBA specification just specifies the high-level functionality that an IMR must provide, and does not specify any of the “look and feel” of an IMR. This means that IMRs differ widely between different CORBA products. For example, the Orbacus IMR is an executable called imr, while the Orbix IMR is an pair of executables: one is called itlocator (the locator daemon) and this is supported by itnode_daemon (the node daemon).

When a server application is registered with an IMR then the IMR can (re-)launch the server. When a server is deployed in this manner, any persistent object references that are exported by the server do not contain the server’s host and port, but rather they contain the host and port of the server’s IMR. When a client tries to invoke upon such an object, the client sends its first invocation to the IMR’s host and port. This gives the IMR a chance to (re-)launch the server if it is not currently running and then redirect the client to the server’s actual host and port.

The main benefit of using an IMR to launch a server is that the server can be re-launched automatically if it ever dies. Some IMRs offer additional benefits. For example, the Orbix IMR can launch several replicas of a server, in order to provide load balancing and fault tolerance. The benefits of having an IMR are desirable in many circumstances. However, there are some reasons why some people prefer to not deploy a server through an IMR:

  1. Many people learn CORBA once piece at a time. Because of this, it is common for a person to know how to develop a CORBA server and how to run it from the command-line, but not (yet) be familiar with how to deploy a server through the IMR.
  2. In many CORBA products the IMR is a single point of failure. Some organizations cannot risk deploying mission-critical applications that have single points of failure. Such organizations often prefer to deploy CORBA systems without using an IMR. An alternative is to develop applications using a CORBA product (such as Orbix) that provides a replicated IMR so that the single point of failure is removed.
  3. Some organizations use a variety of different CORBA products. For example, perhaps one internal project is built using one CORBA product, while another internal project (perhaps in a different department) is built using a second brand name of CORBA product. Finally, the organization may have bought a pre-built CORBA server from a third-party company, and this server was built using a third brand of CORBA product. The system administrator in such an organization is faced with learning how to perform administration tasks with the IMRs of each of the three CORBA products. However, this learning curve could be reduced if some (or all) of the servers could be deployed without an IMR. In this case, the trade-off is to sacrifice the benefits offered by of IMR in order to simplify administration.

An orthogonal issue for server deployment is whether the server will listen on a fixed port or on an arbitrary port that is chosen by the operating system. Such arbitrary ports are often called random, transient (meaning temporary) or ephemeral (meaning short-lived) ports. Use of a fixed port is often desirable if the server is to be accessed by clients across a firewall, or if the server contains PERSISTENT POAs and is being deployed without an IMR. However, most CORBA products will, by default, have servers listens on random ports; this is acceptable if the server contains only TRANSIENT POAs, or if the server contains PERSISTENT POAs but is deployed through an IMR.

Unfortunately, CORBA does not specify the practical details of how to choose:

Instead, such details are left to proprietary extensions provided by each CORBA product. In some CORBA products, these proprietary extensions take the form of command-line options or entries in a configuration file. In other CORBA products, the proprietary extensions take the form of additional APIs, the use of which must be hard-coded into the source code of a server application. This is unfortunate because it hinders source-code portability of CORBA applications. However, the proprietary APIs are typically called when creating either POAs or POA Managers. This makes it possible for the PoaUtility class to encapsulate the use of such proprietary APIs, and so increase source-code portability of server applications, while at the same time deferring deployment decisions until deployment time rather than prematurely deciding them during development.

5.3.1  Specifying a Server Deployment Model with PoaUtility

The constructor of PoaUtility takes a parameter called deployModel that is used to specify how the server is being deployed. The C++ definition of this parameter’s legal values are shown below:

namespace corbautil {
    class PoaUtility {
    public:
        enum DeploymentModel {
            RANDOM_PORTS_NO_IMR, RANDOM_PORTS_WITH_IMR,
            FIXED_PORTS_NO_IMR, FIXED_PORTS_WITH_IMR
        };
        static DeploymentModel
                    stringToDeploymentModel(const char * model)
                                   throw(PoaUtilityException);
    ...
    };
};

Java does not have an enum type so the Java deployment models are denoted as integer constants, as shown below:

package com.iona.corbautil;
abstract public class PoaUtility {
    public static final int RANDOM_PORTS_NO_IMR = 0;
    public static final int RANDOM_PORTS_WITH_IMR = 1;
    public static final int FIXED_PORTS_NO_IMR = 2;
    public static final int FIXED_PORTS_WITH_IMR = 3;
    public static int stringToDeploymentModel(String model)
                throws PoaUtilityException
    ...
};

The four values simply indicate whether or not a server listens on random ports, and whether or not the server is deployed through the IMR. If a CORBA product requires use of proprietary APIs for any of these deployment options then the PoaUtility class calls the appropriate APIs. If a CORBA product does not require use of any proprietary APIs then the PoaUtility class simply ignores the deployModel parameter. In either case, the end user will still have to use the CORBA vendor’s proprietary administration commands, command-line options and/or configuration file entries to set up the necessary environmental support for the chosen deployment model.

The PoaUtility class provides a stringToDeploymentModel() utility method that converts a deployment model string, such as "RANDOM_PORTS_NO_IMR" to the corresponding enum/int value. This utility method performs a case-insensitive string comparison, which means that lower-case strings, such as "random_ports_no_imr" are also acceptable. If an invalid deployment model string (for example, "foo") is passed as a parameter then the method throws a PoaUtilityException that contains a message of the form:

Invalid DeploymentModel "foo"

Use of this utility method makes it trivial for server applications to obtain a deployment model from, say, a command-line option or an entry in a runtime configuration file. This then means that a server’s deployment model can be decided at deployment time rather than being hard-coded during development.

5.3.2  Orbix Server Deployment

If deploying an Orbix server through the IMR then the itadmin utility must be used to register the server with the IMR. Also, whenever starting an IMR-deployable server (either from the command-line or through the IMR) then you must be consistent in specifying the same -ORBname <name> command-line arguments to the server.

If deploying an Orbix server so that it listens on fixed ports then you must indicate the port number used by a POA manager through a configuration variable of the form:3

<label>:iiop:addr_list

where <label> is the label parameter passed to createPoaManager(). Some examples are shown below:

core_functionality:iiop:addr_list  = ["<host>:6000"];
admin_functionality:iiop:addr_list = ["<host>:6001"];

The "<host>" string should be replaced with the name of the computer on which the server is running.

5.3.3  Orbacus Server Deployment

If deploying an Orbacus server through the IMR then the imradmin utility must be used to register the server with the IMR. Also, if you start an IMR-deployable server from the command-line then you must specify -ORBServerId <name> as command-line arguments to the server.

If deploying an Orbacus server so that it listens on fixed ports then you must indicate the port number used by a POA manager through a configuration variable of the form:

ooc.orb.poamanager.<label>.endpoint

where <label> is the label parameter passed to createPoaManager(). Some examples are shown below:

ooc.orb.poamanager.core_functionality.endpoint=iiop –port 6000
ooc.orb.poamanager.admin_functionality.endpoint=iiop –port 6001

5.3.4  TAO Server Deployment

If deploying a TAO server through the IMR then the tao_imr utility must be used to register the server with the IMR. Also, whenever starting an IMR-deployable server (either from the command-line or through the IMR) then you should specify -ORBUseIMR 1 as command-line arguments to the server.

If deploying a TAO server so that it listens on fixed ports then you must indicate the port number used by the server by specifying -ORBEndPoint <endpoint-details> as command-line arguments to the server. An example is shown below:

my_server.exe -ORBEndPoint iiop://foo.acme.com:9999

5.3.5  omniORB Server Deployment

OmniORB does not provide an IMR. Instead, all servers must be started manually. By default, an omniORB server listens on a random port. If you want an omniORB server to listen on a fixed port then you can indicate the port number by specifying -ORBendPoint <endpoint-details> as command-line arguments to the server. An example is shown below:

my_server.exe -ORBendPoint giop:tcp:foo.acme.com:5000

Alternatively, the omniORB configuration file could contain an entry like that shown below:

endPoint = giop:tcp:foo.acme.com:5000

5.4  Using Orbix-proprietary Policies

The PoaUtility class provides access to the Orbix-proprietary policies. For example, you can specify one of the proprietary OBJECT_DEACTIVATION_POLICY values ("deliver", "discard" or "hold") in the list of policies passed as a parameter to createPoa().

Orbix also provides proprietary APIs for creating work queues,4 which can then be associated with POAs. The PoaUtility class provides APIs to access this functionality. C++ code that illustrates this is presented in Section 5.4.1, and corresponding Java code is presented in Section 5.4.2.

5.4.1  C++ Version

The class declaration below shows how to make use of the Orbix-proprietary work queue mechanism.

 1 #include "PoaUtility.h"
 2 using namespace corbautil;
 3 class PoaHierarchy : public PoaUtility
 4 {
 5 public:
 6   PoaHierarchy(CORBA::ORB_ptr               orb,
 7                PoaUtility::DeploymentModel  deployModel)
 8                             throw(PoaUtilityException)
 9   //——–
10   // Accessors
11   //——–
12   WorkQueue_ptr    manual_wq() { return m_manual.wq(); }
13   ... // other accessors
14
15 private:
16   //——–
17   // Instance variables
18   //——–
19   LabelledOrbixWorkQueue        m_auto;
20   LabelledOrbixWorkQueue        m_manual;
21   ... // other instance variables
22 };

The following points should be noted:

The work queues are created and associated with POAs in the body of the constructor, as shown below:

 1 #include "PoaHierarchy.h"
 2
 3 PoaHierarchy::PoaHierarchy(CORBA::ORB_ptr              orb
 4                            PoaUtility::DeploymentModel deployModel)
 5                                      throw(PoaUtilityException)
 6     : PoaUtility(orb, deployModel)
 7 {
 8     //——–
 9     // Create the POA Managers
10     //——–
11     ...
12
13     //——–
14     // Create the work queues
15     //——–
16     m_auto   = createAutoWorkQueue("auto",
17                     1000, 10, 10, 10, 128);
18     m_manual = createManualWorkQueue("manual", 1000);
19
20     //——–
21     // Create the FooFactory POA
22     //——–
23     m_FooFactory = createPoa("FooFactory",
24             root(), m_core_functionality,
25             "user_id + persistent + use_active_object_map_only",
26             m_auto);
27     ...
28 }

The following points should be noted:

5.4.2  Java Version

The class declaration below shows how to make use of the Orbix-proprietary work queue mechanism.

 1 import org.omg.CORBA.*;
 2 import org.omg.PortableServer.*;
 3 import com.iona.corba.IT_WorkQueue.*;
 4 import com.iona.corbautil.*;
 5 class PoaHierarchy
 6 {
 7   public PoaHierarchy(ORB orb, int deployModel)
 8                   throws PoaUtilityException
 9   {
10       PoaUtilityOrbixImpl util = (PoaUtilityOrbixImpl)
11                             PoaUtility.init(orb, deployModel);
12
13       //——–
14       // Create the POA Managers
15       //——–
16       ...
17
18       //——–
19       // Create the work queues
20       //——–
21       m_auto_wq   = util.createAutoWorkQueue("auto",
22                               1000, 10, 10, 10);
23       m_manual_wq = util.createManualWorkQueue("manual", 1000);
24
25       //——–
26       // Create the "FooFactory" POA
27       //——–
28       m_FooFactory =  util.createPoa("FooFactory",
29                               util.root(),
30                               m_core_functionality,
31                               "user_id + transient + "
32                               + "use_active_object_map_only",
33                               m_auto_wq);
34        ...
35    }
36
37   //——–
38   // Accessors
39   //——–
40   public WorkQueue manual_wq()  { return m_manual_wq.wq(); }
41   ...
42
43   //——–
44   // Instance variables
45   //——–
46   private LabelledOrbixWorkQueue     m_auto_wq;
47   private LabelledOrbixWorkQueue     m_manual_wq;
48   ...
49 }

The following points should be noted:

5.4.3  Configuration Values for Work Queues

If the label parameter passed to a work queue creation operation is an empty string then the other parameter values are used directly when creating the work queue. However, if the label parameter is not an empty string then the other parameters can be overridden by runtime configuration entries. If a class has an automatic work queue called "auto" and a manual work queue called "manual") then the corresponding runtime configuration entries can be expressed as shown below:

auto:max_size             = "1000";
auto:initial_thread_count = "10";
auto:high_water_mark      = "10";
auto:low_water_mark       = "10";
auto:thread_stack_size_kb = "512";
manual:max_size           = "1000";

5.5  Porting to Other CORBA Products

5.5.1  C++ Version

The IDL-to-C++ mapping has one annoying hindrance to portability: it does not define the names of CORBA-related header files. The practical effect of this is that a developer must change #include directives for CORBA-related header files when porting an application to a different CORBA product. To alleviate this problem, the author has developed a collection of simple “wrapper” header files that (depending on which #define symbol as been defined) #include product-specific header files. This collection of wrapper header files, which currently supports Orbix, Orbacus, TAO and omniORB, is documented in Chapter 4 (Portability of C++ CORBA Applications). The PoaUtility class uses the portability header files so that it can #include CORBA header files in a portable way.

If you wish to port the PoaUtility class to another CORBA vendor’s product then the first step is to enhance the portability wrapper header files to support that CORBA vendor’s product. In practice, this should take only a few minutes of time. Having done that, the PoaUtility class should then compile cleanly with the other CORBA vendors’ product. However, it will not (yet) take advantage of the CORBA vendor’s proprietary APIs for, say, getting a POA Manager to listen on a fixed port number. To add this capability, you will need to examine the code in PoaUtility.cxx and add some #if...#endif directives as required.

The history of software development has shown that excessive use of #if...#endif directives can result in software that is difficult to read and maintain [SC]. Currently, use of #if...#endif directives is quite localized within the PoaUtility class. However, if this class is extended to support many other CORBA products in the future then proliferation of #if...#endif directives might prove troublesome for code readability and maintainability.

5.5.2  Java Version

The Java approach to producing product-specific implementations of an API is to define the API as either an interface or an abstract class and then use Java’s reflection APIs to dynamically load an appropriate implementation. The canonical example of this for CORBA programmers is org.omg.CORBA.ORB, which is an abstract class. The static init() operation on this class uses reflection to create an instance of the subclass specified by the org.omg.CORBA.ORBClass system property.

The PoaUtility class uses a similar approach. It has a static operation called init(). This operation uses reflection to create an instance of a class using the following algorithm:

  1. If the com.iona.corbautil.PoaUtilityClass system property exists then its value specifies the name of the class to be instantiated.
  2. Otherwise, the org.omg.CORBA.ORBClass system property is examined.
    1. If this property has the value "com.iona.corba.art.artImpl.ORBImpl" then an instance of com.iona.corbautil.PoaUtilityOrbixImpl is created. As its name suggests, this class is an implementation for use with Orbix. Internally, it uses Orbix-proprietary APIs that allow POAs to listen on fixed ports. It also defines additional operations (discussed in Section 5.4) that provide access to the Orbix-proprietary work queues.
    2. If this system property has the value "com.ooc.CORBA.ORB" then an instance of com.iona.corbautil.PoaUtilityOrbacusImpl is created. As its name suggests, this class is an implementation for use with Orbacus. Internally, it uses Orbacus-proprietary APIs that allows a POA manager to listen on a fixed port.
  3. Otherwise, an instance of com.iona.corbautil.PoaUtilityPortableImpl is created. This class uses only CORBA-compliant APIs so it is portable to other CORBA vendor products, but it does not have the ability to allow a POA manager to listen on a fixed port.

The above algorithm could be simplified to just steps 1 and 3. However, step 2 provides a better out-of-the-box experience for Orbix and Orbacus developers because the developers do not need to set up a system property in order for a server to have the ability to listen on a fixed port.

If you want to produce a version of PoaUtility that can take advantage of the proprietary APIs of another CORBA product then you should write a class that inherits from com.iona.corbautil.PoaUtilityPortableImpl and redefines whatever operations it needs to and/or adds new operations.


1
The policy values string can use any combination of whitespace, plus signs or commas as separators between policy names. Also, leading or trailing separators are ignored. This flexibility was chosen in order to facilitate developers who wish to use policy value strings that, say, are obtained from a runtime configuration file or have been generated by a code-generation tool.
2
The policy values string can use any combination of whitespace, plus signs or commas as separators between policy names. Also, leading or trailing separators are ignored. This flexibility was chosen in order to facilitate developers who wish to use policy value strings that, say, are obtained from a runtime configuration file or have been generated by a code-generation tool.
3
Orbix allows individual POAs controlled by the same POA Manager to use different ports; but it also allows POAs controlled by the same POA Manager to share the same port. The PoaUtility class keeps administration simple by allowing the choice of port numbers to be chosen at the relatively coarse granularity of POA Managers rather than at the finer granularity of individual POAs.
4
The discussion in this section assumes the reader is already familiar with the concepts of work queues. If you are not familiar with work queues then you can find details in the Orbix Programmer’s Guide and Programmer’s Reference Guide.

Previous Up Next