[TransWarp] Configuration/binding refinement

Phillip J. Eby pje at telecommunity.com
Mon Jul 8 21:22:50 EDT 2002


At 10:33 PM 7/7/02 -0400, Phillip J. Eby wrote:
>What we end up with, instead, is a simple interface, something like 
>getConfigSetting(propertyname), that's available on all 
>binding.Components.  The default implementation would look things up in a 
>dictionary associated with the component, and if not found, delegate the 
>inquiry to the parent component, unless there is none, in which case 
>request a lookup of the default configuration object, and delegate to 
>that.  Components at each level can potentially cache their response.
>
>...
>
>I haven't given much thought to this style sheet idea as yet, and I don't 
>plan on trying to have it all figured out before implementing a basic 
>configuration-acquiring interface.  But I do want the initial system to 
>support a very limited sort of "pushing" of configuration settings: a 
>component should be able to define a binding for one of its attributes 
>that specifies bindings for parameters of the child object.  Right now, 
>the only way to do this is to subclass the child object as a nested class 
>in the parent object's class.  It would be nice to be able to specify 
>configurations that will apply, regardless of the actual class that ends 
>up filling the spot.  This is important for the naming system in 
>particular, where the exact class of Context object is not going to be 
>known ahead of time, even though the component that needs the context 
>knows what settings it wants to supply to that context.

It looks like the simplest way to implement all of the above will be by 
keying configuration lookups by one or both of an interface and a name, or 
perhaps some sort of parameterized interface.  The result would be that you 
could do the equivalent of Zope 3's "getUtility()" to acquire an object of 
a specified interface.

Components would provide these "utility" objects either as a shared 
instance owned (or weak-reference cached) by the providing component, or as 
a factory which would be called to create a new instance as a component in 
the context of the consuming component.  For example, a "data model" might 
provide an IDBConnection utility as a shared instance, but provide an 
IDBCache utility as a factory which created a distinct cache for each of 
its sub-components needing a cache.

More "traditional" configuration usages, such as setting simple values like 
filesystem directories, e-mail addresses, etc., would be implemented by 
defining an interface for a collection of related configuration data, 
implementing an object that supplied that interface, and then registering 
it as a provided utility.

If we can support parameterized interfaces, then this mechanism can be used 
to replace all sorts of registry mechanisms.  For example, URL context 
factories and URL parsers could simply be registered in context as 
implementations of their respective interfaces, with a parameter indicating 
the URL schemes they supported.  The lookup operation would specify a query 
to be applied to the parameter information, perhaps using a variant of the 
existing "peak.metamodels.querying" package.

There are a few things that would need to be sorted out in order for all 
this to work well.  Mainly, the issue of precedence and overrides within a 
specific registry at the component or application level.  If lookup 
criteria result in more than one possible match at a given level of the 
hierarchy, how is the winner decided?  What if a new provider is registered 
after an old one has already been used?

A simple rule to fix the precedence is that we could make items loaded 
later have lower precedence, which would make the behavior consistent, and 
would make configuration data "include'd" from another configuration file 
be a default, automatically overridden by the more specific, earlier-loaded 
file.  It's also easy to implement as a list.append() operation!

There is only one problem with this rule, as far as I can see, and that's 
that we want dynamic configuration to take precedence over static 
configuration.  This could probably be dealt with by having instances' 
registry attribute binder issue a request for dynamic configuration at 
binding time, before incorporating any class-defined registration.

Interestingly, this could be done by treating the utility registry as 
itself being a utility!  The root-level configuration system could provide 
a utility factory that would look at the component which was asking for a 
utility registry, and hand it one pre-loaded with configuration-supplied 
data...

You know, I think we have a winner here.  There's still a little bit to 
work out about how the interface lookups need to work, and we need to 
define an interface for utility registries.  There's also the question of 
whether utility registries should cache values returned from higher-level 
registries.  I think they can cache instances created above them, or 
factory functions for creating things below them, but not the result of 
calling a factory function.  There will also need to be some metadata for 
indicating whether a utility instance should be held with a weak reference 
or not.  Some objects you'll want to have only hang around as long as 
they're in use, others you want to have live indefinitely.  Last, but not 
least, the parameter and query mechanisms will need to be defined along 
with the interface.




More information about the PEAK mailing list