[omniORB] omniORBpy + wxPython; omniORBpy + Twisted
Stephen Hansen
apt.shansen at gmail.com
Wed Jan 2 00:54:42 GMT 2008
>
> To run:
> - open two terminals
> - in term1 type: python example_echo_srv_wxpython.py
> you should now see the "simple button example" window; press 'Send' to
> note the text window update.
> - copy the IOR from term1, it starts with 'IOR:xxx...xxx'; should be
> able to do this without killing the "simple button example" window
- in term2 type: python example_echo_clt.py IOR:xxx...xxx; where you
> paste in the IOR that was copied from term1; you should see 'Hello from
> Python' in the text window update
As you work with this more yourself, you'll likely find the desire to move a
lot of the lower-level CORBA details into libraries to repeat a lot of this
common setup stuff that would simplify 'using' omniORB in a lot of these
client-ways. Our 'network' library (recently rewritten) has me calling the
"initialize" function once per app, and it sets up the ORB in a common way,
provides a standard method (beyond arguments-- since I found having users
enter standard CORBA arguments on the command line is simply unacceptable)
for specifying endpoints/name servers, and other magical stuff we've added
over the last couple years.
As you go about doing that, some things I've discovered:
- Be very, very careful of calling CORBA.ORB_init in libraries. You only get
one chance to run it with the arguments passed in, and any further
invocations appear to return the same ORB. I found it helpful having my
"initialize" function remember if its called, and then making re-calling it
raise an exception... then have any other network support library check and
raise an exception if they were called before initialize had been.
- In a wx app, let wx be boss. omniORB deals with everything in such an easy
'back seat' way, I found its best to organize the application and deal with
it as any client wxPython app without focusing on the omni-fu. I just call
that initialize function early on in the setup of said app-- usually in the
wxApp's OnInit method. Just always remember: when sending data back to the
GUI, use wx.CallAfter.
- You can call poaManager.activate() anytime; doing so right away as soon as
you initialize the ORB and snag the poa, even before you go about making
servants (that 'ei' is) is helpful (but not necessary). Doing so appears to
be the key catalyst that lets the poa start handling actual requests, but if
there's no requests to handle early, so what. :) I say that because I've
been bitten in forgetting to call it, until I started calling it in the
initialization routine early on :)
You have to copy over the IOR everytime you restart the server, as it
> changes apparently. It is easier to send this to a file and read it, but
> this is a quick little example.
Yeah, it changes everytime; the POA (or the ORB? Or the PoaManager? or
servant itself? I'm not entirely sure on the internals of what does what in
omniORB or CORBA :)) gets a random IP address every invocation. This
actually ends up being quite helpful in certain ways down the road, I've
found. In other ways its vexing. It is a factor to take into consideration
in the design of the application.
You'll likely want to do one of three things in a real app:
1) Set up a Naming Service (omniNames is good, though I use TAO's NT Naming
Service as it is rock solid and runs as a service easily, and our clients
run windows/mac os x primarily) and 'register' this IOR so that other
components/machines can find it (what name you use depends on your app)
2) Specify -ORBendPoint arguments either via the command line or by adding
them to sys.argv passed into ORB_init yourself; this will force a certain
port which will usually have the effect of making a IOR to that computer
keep working as future invocations won't get a random port, but this
specified one.
3) Use an omniINSPOA. This is very nice, but you have to use it carefully;
as much as you'd like to at first you can't create a child POA of it with
different policies. It's best used, I've found, as just a starting point
into an application. You create a very simple interface, "Connector", that
only has two methods on it. One that 'sets' your main interface, and one
that 'gets' it. When your application starts up, you create an Echo_i
servant, and a Connector_i servant. One you're going to use with the
omniORBINSPOA, the other you're going to use with the regular POA.
You then call Echo_i's "set" method with Connector_i's object reference.
That omniINSPOA servant allows you to specify objects by an explicit name.
So you could have your client object reference your server one with a simple
name such as "corbaloc:127.0.0.1:12345/Connector" -instead- of an IOR. That
will always be the same.
It'd be like:
con = orb.string_to_object("corbaloc:127.0.0.1:12345/Connector")
es = con.get()
es.echoString("Hi!")
Those are all very general, I know. There's some good postings on how to
work it around, and I can provide more concrete examples when you get there
:) Which method you do depends on your app... we have a full-blown
application server in python + omniORB with dozens to hundreds of clients
connected to it, and then multiple clients per machine that talk to
each-other. For some of those connections we use a naming service; for some
we use the INSPOA, etc.
> I suppose one can infer from this example that it is feasible (using the
> mechanism you suggested) to drive any wxPython widget as the output of a
> CORBA call from some remote client, which was my interest.
>
Yea, you can;
> I ran the above on Ubuntu; I did not try it on Windows.
>
It -looks- right so it should work on windows and mac also.
> BTW, I did not look at the tic-tac-toe example in detail yet, but it did
> not appear to use the mechanism you suggested as it does not call
> wx.CallAfter.
>
I'm not actually familiar with it; there's alternatives to using
wx.CallAfter.
One is to use a queue, and have an idle loop in the wx thread that checks
that
queue-- but that's what wx.CallAfter does behind the scenes so there's
really no
reason to do that :)
> You will also note that this example does no explicit registration of
> servants with a POA, it simply extends Example__POA.Echo. So, maybe I am
> missing something here.
I use a LOT of "default servants" in my servers-- they save resources and
time and make things easy. And I don't use implicit activation, as it makes
things more complicated if you use more then one POA... like the regular one
or the INS poa.
So in my server initialization code, I do:
defaultRootPOA = orb.resolve_initial_references("RootPOA")
policies = [
defaultRootPOA.create_implicit_activation_policy(
PortableServer.NO_IMPLICIT_ACTIVATION),
]
pman = defaultRootPOA._get_the_POAManager()
pman.activate()
rootPOA = defaultRootPOA.create_POA("motherPOA", pman, policies)
My new poa, a child of the original, doesn't do implicit activation.
My servant would then be initialized as:
echoServant = Echo_i(orb, rootPoa)
rootPoa.activate_object(echoServant)
Later when using the INS poa, that'd be 'activate_object_with_id' to give
that servant a specific name, etc.
Note that the attached file has a specific ordering of the wxPython and
> omniORBpy code; violate the ordering and you may incur an error.
>
I'm not sure what error would be the problem with doing things in a
different order, but I'd naturally do all the network initialization inside
the wxApp's initialization. Just seems natural; wx is boss :) omniORB Just
Works :)
Anyhoo, glad to help. I can help with more specific examples later.
--Stephen.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.omniorb-support.com/pipermail/omniorb-list/attachments/20080102/dcb7b633/attachment-0001.htm
More information about the omniORB-list
mailing list