[TransWarp] Finding an object that provides the interface

Phillip J. Eby pje at telecommunity.com
Wed May 21 15:12:09 EDT 2003


I'm going to tell you *how* to do the things you ask, but first I'm going 
to warn you that I think such "promiscuous registration" is a bad idea.  It 
is not the business of a component I use, to publish itself unbidden to my 
subcomponents.  If I consult a lawyer about one matter, does this give him 
the right to insert himself into all my business matters?

I actually tried what you are doing.  In older versions of PEAK and 
TransWarp, you could do something very similar to this.  It caused 
bugs.  Lots of bugs.  Difficult-to-find bugs.  It is especially problematic 
to do this in a component that is intended for other people's use, because 
they may not know all the interfaces your component publishes itself 
under.  Not only that, but if you do it introspectively as you are 
suggesting, then *you* will not even know, because I could declare that 
some other interface is implied by one of your interfaces, and then your 
component will publish itself under my interface as well!

In short, the approach is an invitation to chaos.  I strongly recommend 
that if you really must do this, you do so only by having the *containing* 
component control the process.  That is, explicitly require the containing 
component to tell the contained component to publish itself.  Maybe 
something like 
'subcomponent.publishYourselfToAllMyChildrenUnderIDontKnowOrCareWhatInterfaces(parent)'.

Okay, so you don't have to use such a name for the method.  But maybe it 
illustrates why I don't think doing this is a good idea.  :)

So how *do* I think you should do this?

class App(binding.Component):

     def __loadMyConfig(self,d,a):
         config.loadConfigFile(self, "MedapE.cfg")

     __loadMyConfig = binding.whenAssembled(__loadMyConfig)

In the config file, define the necessary items in [Provide Utilities], 
under their respective interfaces.  Then, have everything else bindTo the 
interfaces.  Now, what will happen is that the utilities will be created 
with the App as their parent, and everyone will find those single instances 
as the providers.  All the components are now happy.

You will notice that under this approach, there is no need for any of the 
components to know what interfaces they should be published under.  The 
config file takes care of that.

Also, this gets rid of the need for you to have separate configuration 
properties and special loading code, just to create the components.

Now, if after all that, you still insist...  here is how to do what you asked:


At 09:27 PM 5/21/03 +0400, Oleg Broytmann wrote:
> > >   Why findUtility does not find already created instance of
> > >ScenarioServer?
> >
> > Probably because you didn't register it using registerProvider.
>
>    Aha, it is not enough to declare interface. Ok, next bunch of questions:
>How can I list interfaces declared by protocols.advise?

See the 'protocols.IOpenImplementor' interface.  Its methods are called 
(indirectly) by 'protocols.advise()' and other declaration APIs.  The 
metaclass of binding.Component implements these methods; so you can 
subclass them in a custom metaclass to wrap them.


>(That was the
>question I asked already long ago, remember?) What is the component to call
>registerProvider() upon? and what is the provdier? i.e. in the call
>c.registerProvider(iface, provider) what is c and what is provider? Well,
>provider is probably the instance of my class that I want to be found by
>findUtility.

'c' is the component that you want to publish the value from.  'provider' 
is an object that implements config.IRule: i.e. a callable that takes three 
parameters: propertyMap, configKey, targetObject, and returns the 
implementing object.

(This is documented in config.IConfigurable; 'registerProvider' is a method 
of that interface.)




More information about the PEAK mailing list