Re: Schema-by-interface options

Martin Aspeli <[email protected]> Thu, 21 Sep 2006 08:49:46 +0100
Newsgroups gmane.comp.web.zope.plone.archetypes.devel
Message-ID <[email protected]>
Kapil Thangavelu wrote:
> On Wed, 20 Sep 2006 15:46:40 -0700, Martin Aspeli <[email protected]> wrote:

>>   - Does this have any mechanism for adding things to schemas more
>> globally, i.e. install a 'tag' field on all ITaggable or an
>> 'annoyingCorporateContentIdNumber' on all AT objects?
> 
> the primary purpose is providing per instance customization, but the 
> global, flavor on by default is possible, via few means, one is a custom 
> flavorprovider adapter that always returns the global flavors (with 
> adapter specification for either ITaggable or IBaseContent), but doing 
> so requires forgoing marker interface application to content which are 
> applied & removed during flavor lifecycle/mutation management, and which 
> are central feature point of the system, ie. being able to apply both AT 
> schemas, and z3 components at runtime on an instance basis.

Okay, I think I may not understand this completely, probably because I'm 
looking at it from a slightly different perspective. Could you explain 
the original use case(s) by means of an example, just to make sure we're 
on the same page?

>>   - Do you support extended schemas per-class or per-instance?
> 
> per instance, adding an additional per class semantic seems strange in 
> my opinion, in that AT already provides this. i could add an additional 
> semantic for global application of flavors,  although i'm still unclear 
> on the use cases, though its easy enough for integrators to add global 
> semantics with per site customization via an objectcreated event adapter 
> for flavor application in zope 2.10.

Storing schemas persistently per-instance has shown to be troubling in 
the past (migration issues, for one). The two use cases I find most 
difficult at the moment (that my/whit's branches are trying to solve) are:

  - Install product MyNews and the News type gets an extra two fields, a 
new view template and a new action.

In b-org, this is done by registering an appropriate (possibly local) 
adapter for the schema, and possibly changing the FTI upon install.

  - Install product MyTagging, which applies ITaggable to a bunch of 
content types. ITaggable implies that these content types also have a 
'tag' field in their schema.

In b-org, this is done by registering a new ISchemaExtender adapter. On 
my branch, I've tried to generalise this a bit - you adapt self to 
ISchemaComposer to get back a single schema, and this in turn look up 
all adapters from (context, composer) to ISchemaProvider, which can 
provide fragments of a schema. The default provider just looks as 
klass.schema (and there is caching going on). Providers are ordered.

>>   - Is it possible for a particular flavor to be installed in one Plone
>> site but not in another (in the same Zope instance)
> 
> flavors are mostly just sugar around adapters, a local component 
> registry, and changing all the adaptation lookups to provide context ( 
> assuming some appropriate icomponentlookup adapters for AT content) 
> would allow for this.

You don't need to pass 'context' to adapter/utility lookups to have it 
prefer local adapters over global ones (at least not in Zope 2.10) - 
Zope 3's threadlocal acquistion knows which component registry to use, 
and falls back on the global by default. In *tests* you need to call 
setHooks(), setSite(ploneSite), but that's about it.

> however the system is currently targeting z2.9 and 
> plone 2.5, because we need it production now for a high traffic site, 
> and considering the new component registry machinery in zope 3.3, its 
> not worthwhile to investigate/implement till the system is ported to 
> zope 2.10.

My efforts are targetted at 3.0, so I can neatly sidestep that issue. :) 
But yeah, hopefully it'll "just work".

>>   - Do you cache schemas in a _v_ attribute only? This may have a
>> performance impact; the approach on my branch and in b-org uses a cache
>> (keyed by __class__) that needs to be explicitly invalidated (via an
>> event). Maybe I'm missing something though.
> 
> the class cache is a broken semantic, if you want to be being able to 
> apply by instance. 

Definitely. I probably need to generalise that, actually. Per-instance 
is less interesting to me (I may be wrong), but I certainly don't want 
to make it impossible to do per-instance with the appropriate adapters.

> once you have per instance semantics, caches become 
> tricky, due to the need for at initialization of accessors/mutators per 
> instance, and you have the notion of ordered schemas which allow for 
> field overriding, or class directly implementing custom 
> accessors/mutators for applied schemas. that said there are some 
> potential optimizations here for a smart cache, with a lookup of (class, 
> flavor name tuple) -> (schema, accessor/mutator dict) for limiting 
> memory consumption and composition.

The thing that shot down VariableSchemaSupport and friends was always 
that it'd do the ClassGen dance on every or almost every access to 
Schema(), which is very slow. With Z3 events, I see no problem in having 
a cache that's explicitly invalidated in an event handler, since the 
code that mutates the schema can fire the event. The hard part is 
picking the right cache key.

>>   - Why is the FlavorUtility not registered as a utility?
> 
> because it was a decoy, its been removed, this code has been under 
> active development all day ;-) its stable after as of this email, in 
> that feature development is complete.

Oh, great. I'll try to check it out later. If I take a more active 
interest in it, could we shift it to the AT svn repo or the Collective? 
I'll branch of course!

> the at minimal mixin the system needs is in aware.py..  basically just 
> delegates for Schema() and getIcon(), the schema delegation could be any 
> such implementation that defers to the CA for an adapter, and 
> contentflavors could integrate for management, though i have questions 
> regarding getting the z3 management ui view on applicable adapatable 
> content, without a declared interface on the content.

You can apply interfaces from outside the package, though, with 
alsoProvides() or <five:implements>.

>>     For example, I could imagine that we could go back to Whit's
>> original schema-by-iface implementation which only adapts self to
>> ISchema (I have some issues with his implementation, though I think it
>> can be made nicer with a custom adapter factory method), and then let
>> ContentFlavors handle the actual use cases for extension.
> 
> yes, this is possible, minus the icon use cases which i'm happy to forgo 
> for more generic integration scenarios, as making this functionality 
> useful in plone 2.5 requires custom navtree/folder content components 
> and are project specific anyways. when the type specific css icons go 
> away in plone 3.0, it might be worth consideration again for generic 
> integration.

Indeed. I think it'd be nice if kept the incisions in AT minimal, so 
long as we could try to work together to have *one* add-on product that 
allowed for more dynamic schema composition ala Flavors. So, if you want 
Flavors to be able to manage all content types generically, then it may 
have to plug itself into BaseObject via an adapter that's either in 
overrides.zcml or on a specific marker interface. If some other product 
tried to do the same, the two may conflict or one may take precedence 
over the other. That's an argument for keeping the schema composition in 
Products.Archetypes, but if we can either just make sure we don't 
re-invent that functionality or somehow make BaseObject's schema (and 
icon?) delegation clever enough, we could mitigate that.

>>    The main problem is that, as you've discovered, you need to
>> re-generate methods ClassGen style when things change (and at least
>> once) at run-time, since ClassGen is only run once and is only aware of
>> the 'schema' class-attribute. This has performance implications, if
>> nothing else. I'd rather that functionality was in AT.
>>
> 
> such functionality is already duplicated elsewhere (atseng comes to 
> mind) to support different semantics, one implementation to rule them 
> all doesn' really seem all that z3ish ;-)

That's true. But if AT says, "I support the application of schemas by an 
adapter lookup", then that *does not work* without calling a 
ClassGen'ish thing at least once (after the lookup of the schema has 
been made the first time). This is because AT's basic ClassGen works at 
class loading time, and cannot do the adapter lookup (no context), and 
it relies on the .schema class-variable, which cannot be made dynamic 
like an instance-variable could wither @property. So, I think it'd dumb 
to support some way of delegating schemas to an adapter if you know that 
anyone who actually uses that functionality *must* do a dance with 
generating methods, opening that up to re-invention and bugs and 
possibly conflicts.

>>   - s/Flavors/Flavours/g (may not win that one...)
> 
> i hated the name before i started.. but went with it to minimize 
> introducing new client vocabulary, as alternatives we considered Facets 
> and Behaviors, facets sounded better, behaviors denote some more AOP 
> style semantics then i think are actually given. but i'm out of time to 
> do name refactoring, though patches would be welcome.

It'll do. :)

Martin

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV