[Zope3-dev] Context and Component Lookup

Jim Fulton jim@zope.com
Wed, 06 Aug 2003 06:57:56 -0400


This is, essentially a proposal. It is here, rather than the Wiki due
to the birthing pains of new zope.org. :)

As things stand now, component lookup is based on location. For
example, suppose we have two sites, S1 and S2 that are both in the
root folder. The root folder is also a site.  Now, suppose we have
object O in site S1.  If we look up an adapter for O:

   a = getAdapter(O, IFoo)

we'll look for an adapter factory in S1, then in the root site, and
finally in the global adapter service.  This is all well and good, I
think. Note that to do this, we use contextual information for O. For
example, now, we use the context wrapper around O to figure out where
it is. In the future we might use a __container__ attribute of O.

Now, supposer we access a subobject of O, O.x. Further, suppose
we don't have context information for O.x:

   x = O.x
   a = getAdapter(x, IBar)

Now, because x doesn't have any context information, we'll only look
in the global adapter service.  This is likely to lead to unpleasant
surprises if S1 or the root site defined an applicable adapter.

Now consider a slightly different case. Suppose we access a view of O
in S1 via a URL:

   http://eek.com/S1/O/someview.html

So we have a request in S1. Now suppose that in that view, we access
object P from S2.  We use a view, V, of P in generating the output
(for the view of O in S1).  There are different definitions of this
view in S1 and S2. Which one should we use?  I'm inclined to think
that we should use the one from S1 (but this inclination is a bit self
serving ;).

What the example above suggests to me is that perhaps a request should
decide the place for component lookup rather than the objects that the
request uses.  A request has a location, defined by the URL.  Perhaps
*that* should define the *single* place for that request where all
component lookup happens.  I argue that this is better that using
object location for two reasons:

1. It provides a consistent "domain" for component lookup for a
    request.  This seems especially compelling for views, but I think
    it would be easier to reason about a request if component lookup is
    consistent.

2. It is less brittle with regard to determination of location. We can
    pretty unambiguously decide the location of a request, but not all
    objects carry enough information to determine their location.

An additional benefit of the simpler component lookup strategy
suggested here is that it can be implemented more efficiently and
cached more effectively.

Note, however, that this simpler strategy would *not* apply to
security information.  In a location-based security policy, the actual
object location will be used to determine access.

To implement this simpler component lookup strategy will require
resorting to a thread-global variable. This thread global variable
will be set during URL traversal and (probably) cleared when a request
is closed.  In the unlikely event that a thread spawns a new thread,
the global variable would be carried to the subthread, providing that
a specialized API is used to spawn the subthread.  I don't really like
using thread globals (or any globals, for that matter), however, I
think that this is a case where the improvement in simplicity and
efficiency of component lookup justifies the global variable.

Finally, I'll note that the component lookup policy will be
pluggable. Alternative policies can be configured.

Thoughts?

-- 
Jim Fulton           mailto:jim@zope.com       Python Powered!
CTO                  (703) 361-1714            http://www.python.org
Zope Corporation     http://www.zope.com       http://www.zope.org