<div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">To run:<br>- open two terminals<br>- in term1 type: python example_echo_srv_wxpython.py<br>you should now see the "simple button example" window; press 'Send' to
<br>note the text window update.<br>- copy the IOR from term1, it starts with 'IOR:xxx...xxx'; should be<br>able to do this without killing the "simple button example" window</blockquote><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
- in term2 type: python example_echo_clt.py IOR:xxx...xxx; where you<br>paste in the IOR that was copied from term1; you should see 'Hello from<br>Python' in the text window update</blockquote><div><br class="webkit-block-placeholder">
</div><div><br class="webkit-block-placeholder"></div><div><div>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.
</div><div><br class="webkit-block-placeholder"></div><div>As you go about doing that, some things I've discovered:</div><div><br class="webkit-block-placeholder"></div><div>- 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.
</div><div>- 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.</div><div>- 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 :)
</div><div><br class="webkit-block-placeholder"></div></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">You have to copy over the IOR everytime you restart the server, as it
<br>changes apparently. It is easier to send this to a file and read it, but<br>this is a quick little example.</blockquote><div><br class="webkit-block-placeholder"></div><div>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.
</div><div><br class="webkit-block-placeholder"></div><div>You'll likely want to do one of three things in a real app:</div><div><br class="webkit-block-placeholder"></div><div>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)
</div><div>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.
</div><div>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.
</div><div><br class="webkit-block-placeholder"></div><div>You then call Echo_i's "set" method with Connector_i's object reference. </div><div><br class="webkit-block-placeholder"></div><div>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:
<a href="http://127.0.0.1:12345/Connector">127.0.0.1:12345/Connector</a>" -instead- of an IOR. That will always be the same. </div><div><br class="webkit-block-placeholder"></div><div>It'd be like:</div><div> con =
orb.string_to_object("corbaloc:<a href="http://127.0.0.1:12345/Connector">127.0.0.1:12345/Connector</a>")</div><div> es = con.get()</div><div> es.echoString("Hi!")</div><div><br></div><div>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.
</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">I suppose one can infer from this example that it is feasible (using the<br>mechanism you suggested) to drive any wxPython widget as the output of a
<br>CORBA call from some remote client, which was my interest.<br></blockquote><div><br></div><div>Yea, you can; </div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
I ran the above on Ubuntu; I did not try it on Windows.<br></blockquote><div><br class="webkit-block-placeholder"></div><div>It -looks- right so it should work on windows and mac also.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
BTW, I did not look at the tic-tac-toe example in detail yet, but it did<br>not appear to use the mechanism you suggested as it does not call<br>wx.CallAfter.<br></blockquote><div><br class="webkit-block-placeholder"></div>
<div>I'm not actually familiar with it; there's alternatives to using wx.CallAfter.</div><div>One is to use a queue, and have an idle loop in the wx thread that checks that</div><div>queue-- but that's what wx.CallAfter
does behind the scenes so there's really no</div><div>reason to do that :) </div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">You will also note that this example does no explicit registration of
<br>servants with a POA, it simply extends Example__POA.Echo. So, maybe I am<br>missing something here.</blockquote><div><br class="webkit-block-placeholder"></div><div>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.
<br></div><div><br class="webkit-block-placeholder"></div><div>So in my server initialization code, I do:</div><div><br class="webkit-block-placeholder"></div><div> defaultRootPOA = orb.resolve_initial_references("RootPOA")
<br class="webkit-block-placeholder"></div><div><div> policies = [</div><div> defaultRootPOA.create_implicit_activation_policy(PortableServer.NO_IMPLICIT_ACTIVATION),</div><div> ]</div><div><br class="webkit-block-placeholder">
</div><div> pman = defaultRootPOA._get_the_POAManager()</div><div> pman.activate()</div><div> rootPOA = defaultRootPOA.create_POA("motherPOA", pman, policies)</div><div><br class="webkit-block-placeholder">
</div><div>My new poa, a child of the original, doesn't do implicit activation. </div><div><br></div><div>My servant would then be initialized as:</div><div><br class="webkit-block-placeholder"></div><div><div> echoServant = Echo_i(orb, rootPoa)
</div><div> rootPoa.activate_object(echoServant)<br></div><div> </div><div>Later when using the INS poa, that'd be 'activate_object_with_id' to give that servant a specific name, etc.</div><div><br class="webkit-block-placeholder">
</div></div></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">Note that the attached file has a specific ordering of the wxPython and<br>omniORBpy code; violate the ordering and you may incur an error.
<br></blockquote><div><br class="webkit-block-placeholder"></div><div>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 :)
</div><div><br></div><div>Anyhoo, glad to help. I can help with more specific examples later.</div><div><br class="webkit-block-placeholder"></div><div>--Stephen.</div></div>