Back to index

plone3  3.1.7
registry.py
Go to the documentation of this file.
00001 import Acquisition
00002 import OFS.ObjectManager
00003 from Acquisition.interfaces import IAcquirer
00004 from zope.app.component.hooks import getSite
00005 from zope.app.component.interfaces import ISite
00006 from zope.component.persistentregistry import PersistentAdapterRegistry
00007 from zope.component.persistentregistry import PersistentComponents
00008 from zope.component.registry import UtilityRegistration
00009 from zope.interface.adapter import VerifyingAdapterLookup
00010 from zope.interface.adapter import _lookup
00011 from zope.interface.adapter import _lookupAll
00012 from zope.interface.adapter import _subscriptions
00013 from ZPublisher.BaseRequest import RequestContainer
00014 
00015 from five.localsitemanager.utils import get_parent
00016 
00017 _marker = object()
00018 
00019 class FiveVerifyingAdapterLookup(VerifyingAdapterLookup):
00020 
00021     # override some AdapterLookupBase methods for acquisition wrapping
00022 
00023     def _uncached_lookup(self, required, provided, name=u''):
00024         result = None
00025         order = len(required)
00026         for registry in self._registry.ro:
00027             byorder = registry._adapters
00028             if order >= len(byorder):
00029                 continue
00030 
00031             extendors = registry._v_lookup._extendors.get(provided)
00032             if not extendors:
00033                 continue
00034 
00035             components = byorder[order]
00036             result = _lookup(components, required, extendors, name, 0,
00037                              order)
00038             if result is not None:
00039                 result = _wrap(result, registry)
00040                 break
00041 
00042         self._subscribe(*required)
00043 
00044         return result
00045 
00046     def _uncached_lookupAll(self, required, provided):
00047         order = len(required)
00048         result = {}
00049         for registry in reversed(self._registry.ro):
00050             byorder = registry._adapters
00051             if order >= len(byorder):
00052                 continue
00053             extendors = registry._v_lookup._extendors.get(provided)
00054             if not extendors:
00055                 continue
00056             components = byorder[order]
00057             tmp_result = {}
00058             _lookupAll(components, required, extendors, tmp_result, 0, order)
00059             for k, v in tmp_result.iteritems():
00060                 tmp_result[k] = _wrap(v, registry)
00061             result.update(tmp_result)
00062 
00063         self._subscribe(*required)
00064 
00065         return tuple(result.iteritems())
00066 
00067     def _uncached_subscriptions(self, required, provided):
00068         order = len(required)
00069         result = []
00070         for registry in reversed(self._registry.ro):
00071             byorder = registry._subscribers
00072             if order >= len(byorder):
00073                 continue
00074 
00075             if provided is None:
00076                 extendors = (provided, )
00077             else:
00078                 extendors = registry._v_lookup._extendors.get(provided)
00079                 if extendors is None:
00080                     continue
00081 
00082             tmp_result = []
00083             _subscriptions(byorder[order], required, extendors, u'',
00084                            result, 0, order)
00085             result = [ _wrap(r, registry) for r in result ]
00086 
00087         self._subscribe(*required)
00088 
00089         return result
00090 
00091 
00092 def _recurse_to_site(current, wanted):
00093     if not Acquisition.aq_base(current) == wanted:
00094         current = _recurse_to_site(get_parent(current), wanted)
00095     return current
00096 
00097 def _wrap(comp, registry):
00098     """Return an aq wrapped component with the site as the parent but
00099     only if the comp has an aq wrapper to begin with.
00100     """
00101 
00102     # BBB: The primary reason for doing this sort of wrapping of
00103     # returned utilities is to support CMF tool-like functionality where
00104     # a tool expects its aq_parent to be the portal object. New code
00105     # (ie new utilities) should not rely on this predictability to
00106     # get the portal object and should search out an alternate means
00107     # (possibly retrieve the ISiteRoot utility). Although in most
00108     # cases getting at the portal object shouldn't be the required pattern
00109     # but instead looking up required functionality via other (possibly
00110     # local) components.
00111 
00112     if registry.__bases__ and IAcquirer.providedBy(comp):
00113         current_site = getSite()
00114         registry_site = Acquisition.aq_base(registry.__parent__)
00115         if not ISite.providedBy(registry_site):
00116             registry_site = registry_site.__parent__
00117 
00118         if current_site is None:
00119             # If no current site can be found, return utilities wrapped in
00120             # the site they where registered in. We loose the whole aq chain
00121             # here though
00122             current_site = Acquisition.aq_base(registry_site)
00123 
00124         parent = None
00125 
00126         if current_site == registry_site:
00127             parent = current_site
00128         else:
00129             parent = _recurse_to_site(current_site, registry_site)
00130 
00131         if parent is None:
00132             raise ValueError('Not enough context to acquire parent')
00133 
00134         base = Acquisition.aq_base(comp)
00135         # clean up aq_chain, removing REQUEST objects
00136         parent = _rewrap(parent)
00137 
00138         if base is not Acquisition.aq_base(parent):
00139             # If the component is not the component registry container,
00140             # wrap it in the parent
00141             comp = base.__of__(parent)
00142         else:
00143             # If the component happens to be the component registry
00144             # container we are looking up a ISiteRoot.
00145             # We are not wrapping it in itself but in its own parent
00146             comp = base.__of__(Acquisition.aq_parent(parent))
00147 
00148     return comp
00149 
00150 def _rewrap(obj):
00151     obj = Acquisition.aq_inner(obj)
00152     base = Acquisition.aq_base(obj)
00153     parent = Acquisition.aq_parent(obj)
00154     if not parent or isinstance(parent, RequestContainer):
00155         return base
00156     return base.__of__(_rewrap(parent))
00157 
00158 
00159 class PersistentComponents \
00160           (PersistentComponents,
00161            OFS.ObjectManager.ObjectManager):
00162     """An implementation of a component registry that can be persisted
00163     and looks like a standard ObjectManager.  It also ensures that all
00164     utilities have the the parent of this site manager (which should be
00165     the ISite) as their acquired parent.
00166     """
00167 
00168     def _init_registries(self):
00169         super(PersistentComponents, self)._init_registries()
00170         utilities = Acquisition.aq_base(self.utilities)
00171         utilities.LookupClass = FiveVerifyingAdapterLookup
00172         utilities._createLookup()
00173         utilities.__parent__ = self
00174 
00175     def registeredUtilities(self):
00176         for ((provided, name), (component, info)
00177              ) in self._utility_registrations.iteritems():
00178             yield UtilityRegistration(self, provided, name,
00179                                       _wrap(component, self), info)