[omniORB] omniORBpy 3.0 sample code and some questions

Duncan Grisby dgrisby@uk.research.att.com
Mon, 08 May 2000 18:28:29 +0100


On Monday 8 May, "Chris Knight" wrote:

> Needless to say, a full day's work (scanning the mailing list and
> reverse-engineering omniORBpy) to generate such a simple example makes me
> think that more (better?) Python examples need to be generated (by us, the
> user community?)  What say you?  (In particular, I'm looking for some DII
> examples.)

omniORBpy is indeed lacking documentation at the moment. It's on the
list of things to do... If you haven't already, I strongly recommend
that you read the Python mapping specification, since that tells you
almost everything you need to know:

  http://www.omg.org/cgi-bin/doc?ptc/00-01-12

On the subject of DII, it isn't supported in omniORBpy, for two
reasons. Firstly, the Python mapping for DII requires an interface
repository, which omniORB doesn't have. Secondly, and more
importantly, it is much easier to construct dynamic requests using
Python's normal dynamic facilities (exec, apply, etc.), rather than
the inconvenient DII interfaces.

If you need to deal with interfaces you haven't seen when the program
starts up (i.e. you don't have omniidl generated stubs for them), you
can use omniORB.importIDL() and omniORB.importIDLString() to generate
them at run-time.

Anyway, I have a few comments about your code. Sorry for the long
quote, but I want to keep the context...

> module ChatApp
> {
>         interface ChatClientCallBack
>         {
>                 attribute string id;
>                 void printmessage (in string message);
>         };
>         interface ChatServ
>         {
>                 void register(in ChatClientCallBack ClientObj);
>                 void broadcastmessage(in ChatClientCallBack ClientObj, in
> string message);
>         };
> };

> ---Here's the code---
> import sys
> import omniORB

I'd advise using 'from omniORB import CORBA', rather than 'import
omniORB', since that isolates the omniORB-specific bit to the import
statement. Everything else will (in theory) be portable between ORBs.

> import POA_ChatApp

You're also going to need 'import ChatApp' here, as I'll explain
below...

> import CosNaming
> 
> print 'What is your name?',
> name = sys.stdin.readline()[:-1]
> orb = omniORB.CORBA.ORB_init(sys.argv, omniORB.CORBA.ORB_ID)

With the 'from omniORB...' change, this would become 'orb =
CORBA.ORB_init(sys.argv, CORBA.ORB_ID)'

> poa = orb.resolve_initial_references('RootPOA')
> poaManager = poa._get_the_POAManager()
> poaManager.activate()
> 
> class Callback(POA_ChatApp.ChatClientCallBack):
>         def __init__(self, name):
>                 self.name = name
> 
>         def _get_id(self, *args):

_get_id() doesn't ever have any arguments, so it's clearer to say

          def _get_id(self):

>                 return self.name

In the IDL, id is declared as an attribute, not a readonly attribute,
so you should also provide a _set_id(self, name) method, or declare id
as readonly. If someone was to call _set_id() they would get a
CORBA::NO_IMPLEMENT exception, so this omission isn't a disaster.

>         def printmessage(self, message): print `message`
> 
> callback = Callback(name)
> callbackobj = callback._this()
> 
> nsobj = orb.resolve_initial_references('NameService')
> nc = CosNaming.NameComponent('ChatServ', ' ')
> chatserv = nsobj.resolve([nc])

This line is correct, but it might come back to bite you later.
CosNaming::NamingContext::resolve() returns the base CORBA::Object
type. In your program, the object you get is actually of type
ChatApp::ChatServ, which is the type you are expecting, so everything
works.

However, suppose someone creates an object with interface:

  interface DerivedChatServ : ChatApp::ChatServ {};

Now, if the resolve() returns a reference to that object, your program
won't know the DerivedChatServ interface, so chatserv will just be of
type CORBA.Object, rather than ChatApp::ChatServ as you want.

To be on the safe side, you should actually do:

  obj = nsobj.resolve([nc])
  charserv = obj._narrow(ChatApp.ChatServ)

(which is why you need to import ChatApp as well as just POA_ChatApp)

> chatserv.register(callbackobj)

Note that in the implementation of register(), you _don't_ need to
worry about the object being of a derived type you don't know. The IDL
says that the object is a ChatApp::ChatClientCallBack, so even if it
receives a type it doesn't know, it gives it the benefit of the doubt,
and assumes it is OK. The first time you contact the object, it checks
that it is really the right type.

_narrow() is only necessary when the IDL gives insufficient static
type information for the ORB to know what type you (the programmer)
are expecting.


Separate from all that discussion, with the Interoperable Naming
Service (INS) support (which you have if you have a recent checkout of
omniORB 3), you can replace all the naming service stuff with:

  obj = orb.string_to_object("corbaname:rir:#ChatServ")
  chatserv = obj._narrow(ChatApp.ChatServ)

which is much nicer than constructing lists of NameComponents. The
string indicates that the ORB should contact the NameService returned
by resolve_initial_references(), and resolve the entry with name
"ChatServ". Note that the name service you run does not have to be one
which knows about INS for this to work.

> while 1:
>         print 'Type something:',
>         a = sys.stdin.readline()[:-1]
>         chatserv.broadcastmessage(callbackobj, a)

This bit's OK!  :-)

Some time soon, I'll get around to writing some proper documentation
which will cover all this.

Cheers,

Duncan.

-- 
 -- Duncan Grisby  \  Research Engineer  --
  -- AT&T Laboratories Cambridge          --
   -- http://www.uk.research.att.com/~dpg1 --