[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