[TransWarp] Re: [Zope3-dev] EventService, references, and subscription
semantics
Phillip J. Eby
pje at telecommunity.com
Tue Feb 26 07:40:01 EST 2002
Okay, maybe I'm missing something, but it seems to me like the simplest
decomposition would be:
1. 'IReferenceable' - interface with a 'getReference()' method, returns a
reference to the referencable thing.
2. 'IReference' - subclass of IReferenceable, whose implementations'
'getReference()' methods return 'self'. Includes a 'dereference()' method,
as well as '__eq__()' and '__hash__()' (general comparison doesn't really
make sense for references, but dictionary lookup and equality checking
would be useful). 'IReference' objects should be immutable and
pickle-able, but should probably *not* be Persistent (the overhead would be
wasteful).
3. Things that need references, use 'getAdapter()' to get an
'IReferenceable' implementation for the thing they want a reference to.
4. You're done. :) Since 'IReference' is a subclass of 'IReferencable',
if you were passed a reference, you've got what you need. If you didn't
have a reference, then you'll get something that can give you one. All the
lookup policies that y'all are talking about can be encapsulated in the
adapter that implements IReferenceable, and configured via the normal
channels. If 'getAdapter()' is insufficiently placeful, make the adapter
do placeful lookups and delegate to the appropriate authorities.
How's that sound? I think it would also be nice if there was a way to
convert a reference to a short text string that could be turned back into
an object, for non-pickling purposes, but that might be a little too
ambitious. OTOH, Ty and I have successfully used the following pattern for
references in other applications:
Consider a reference to be a URL of the form "scheme:opaquedata". Since
the RFC's say a URL scheme may include '"."' characters, a dotted path to a
class or function in a Python module may be used. Implement a general
lookup function which loads the scheme implementation, and then calls it
with the full URL string, to receive an object.
This concept has served us especially well for referencing various kinds of
objects such as SQL and LDAP database connections, logfiles, lockfiles,
etc. We use it in conjunction with a simple configuration file format that
maps symbolic names to URL references. Code then refers to symbolic names
such as "applicationDatabase", which are looked up in the configuration
file and converted to a URL, before being converted into the actual object
needed by the application.
A similar pattern, implemented in Zope3, would extend the reach of ZCML
considerably, to reference arbitrary objects inside *or* outside the
ZODB. Interestingly, it could be implemented in a way that would be
backward compatible with existing "module.class" references, since they do
not use the '":"' character currently.
I was just in the process a few days ago of designing a more general
version of our current reference facilities to incorporate into
TransWarp. If there is interest on the Z3 side, perhaps we could create a
joint specification for object naming based on this URL pattern, or even a
joint implementation for Zope and TransWarp. I've been studying the Java
JNDI naming specs, and a lot of what's there could be applied to Zope
naming, but in the short-term I only intend to work on the URL part.
The relevant part from JNDI is that one can configure a "package path" for
URL schemes, which is a set of package prefixes that are added to the
scheme name in succession until a loader is found. So, if the package path
were '["Zope.Naming", "TW.Naming"]', the URL '"foo.spam:bar/baz"' would
cause a lookup of 'Zope.Naming.foo.spam.', then 'TW.Naming.foo.spam.', and
the first item found would be taken. I think that for Python, the
convention should try the bare 'foo.spam' first, *if* it contains a dot.
Of course, configuring the package path could be done from ZCML... :) (as
well as from Python code and perhaps an environment variable)
I was originally thinking that I would implement this logic in a TW.Naming
package for TransWarp. However, I would not be averse to creating a
separate distribution package - PyNDI perhaps? - that could be shared by
Zope, TransWarp, and any other Python application that could use this sort
of capability. ZCML could then convert reference strings to PyNDI.URL
objects, which would implement IReference. IReference and IReferenceable
would actually be defined and exported by the PyNDI package.
Over the somewhat longer term, PyNDI could be expanded to implement JNDI's
other concepts such as naming contexts, which I think could be very useful
in relation to Zope concepts of traversal and namespace manipulation.
What do y'all think? I was planning to implement a rudimentary form of
this sometime in the next couple of weeks, anyway. The only real question
is whether I should implement it as TW.Naming or PyNDI... :) (Well,
actually, I imagine that the ZC folks will want to add a bit more "process"
before implementation, but that's okay by me.)
At 09:01 AM 2/26/02 +0000, Steve Alexander wrote:
>Shane Hathaway wrote:
>>
>>That sounds reasonable for this case, but I don't think we've had enough
>>time to think to be designing a service yet. Maybe we have, but I'd like
>>us to leave room for adding an event subscriber that either provides its
>>own reference, or doesn't need to use a reference at all.
> >
>>Hmm, maybe that's not a problem: the addSubscriber() method of the event
>>service (or whatever the method is called) might accept either a reference
>>object or some other kind of object; if the object is not a reference then
>>the event service tries to make one for it. That's a similar pattern to
>>what getAdapter() does.
>
>I suggest that this isn't the job of the subscribe() method of the
>EventService. The ReferenceService (as in the diagram in my last email)
>could just return the object if it already implements IReference.
>>I think IReferenceLookup is the wrong name--I think what you want is
>>something like IReferenceGenerator. The IReferenceGenerator is only used
>>when creating a reference, not when dereferencing one, which the name
>>"IReferenceLookup" tends to imply (although the implementation might, at
>>its option, refer to the IReferenceGenerator that created it in order to
>>dererence.)
>
>Sure. It is good to have more accurately descriptive names :-)
>
>So, heres what we have so far. I guess I should put this on a wiki soon.
>
>
>Either an object can be its own IReference, or the object's context
>provides a utility to say how to make an appropriate kind of reference, or
>the IReferenceGenerator utility/service provides IReferences, based on
>sensible zcml configured defaults.
>
>
> Root :-- IReferenceGenerator (service/utility)
> / \
> Bar Foo
> / \
> Baz LDAPUserFolder :-- IReferenceGeneratorForContext (utility)
> \
> LDAP Principal Object
>
>
>So, object Baz gets the LDAP Principal Object (let's call it "user"). It
>wants to store a reference to user. Baz might well be an IEventService, or
>other kind of ISubscribable object.
>
> 1: Baz gets the IReferenceGenerator service
>
> 2: Baz passes user to the IReferenceGenerator service
>
> 3: If user implements IReference, the IReferenceGenerator service
> simply returns user as its own IReference.
>
> 4: Otherwise, the IReferenceGenerator service examines user's context
> wrapper, and walks the wrapper looking for an
> IReferenceGeneratorForContext utility.
>
> 5: The IReferenceGenerator service passes user to the
> IReferenceGeneratorForContext utility, which returns an appropriate
> IReference object.
>
> 6: If the IReferenceGeneratorForContext service returns None, or if it
> can't be found, the IReferenceGenerator service does whatever it
> is configured (by zcml directives perhaps) to do, such as return
> a simple default IReference for the object.
>
>
>What about comparing IReferences. I think I'd like IReference to implement
>__cmp__ or something, and have some appropriate semantics.
>
>--
>Steve Alexander
>
>
>_______________________________________________
>Zope3-dev mailing list
>Zope3-dev at zope.org
>http://lists.zope.org/mailman/listinfo/zope3-dev
More information about the PEAK
mailing list