Commit 001cd87a authored by Julien Muchembled's avatar Julien Muchembled

Stop using zope.site.hooks and implement our own getSite using ERP5Site.__of__

zope.site.hooks.setSite is always called too late to be usable and it became
a nightmare to make getSite working early enough.

This fixes portal creation on Zope 2.12, which was broken since r38613.

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@38691 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 21c89103
......@@ -67,7 +67,6 @@ except ImportError:
from ZODB.POSException import ConflictError
from Products.MailHost.MailHost import MailHostError
from zope.site.hooks import setSite
from zLOG import LOG, INFO, WARNING, ERROR
from warnings import warn
......@@ -878,9 +877,6 @@ class ActivityTool (Folder, UniqueObject):
if not acquired:
return
portal = self.getPortalObject()
setSite(portal)
# make sure our skin is set-up. On CMF 1.5 it's setup by acquisition,
# but on 2.2 it's by traversal, and our site probably wasn't traversed
# by the timerserver request, which goes into the Zope Control_Panel
......
......@@ -15,6 +15,8 @@
Portal class
"""
import threading
from weakref import ref as weakref
from Products.ERP5Type import Globals
from Products.ERP5Type.Globals import package_home
......@@ -36,8 +38,7 @@ from Products.ERP5Type.Log import log as unrestrictedLog
from Products.CMFActivity.Errors import ActivityPendingError
import ERP5Defaults
from Products.ERP5Type.TransactionalVariable import getTransactionalVariable
from zope.site.hooks import setSite
from Products.ERP5Type.Dynamic.portaltypeclass import synchronizeDynamicModules
from zLOG import LOG, INFO
from string import join
......@@ -178,6 +179,38 @@ class ReferCheckerBeforeTraverseHook:
'request : "%s"' % http_url)
response.unauthorized()
class _site(threading.local):
"""Class for getting and setting the site in the thread global namespace
"""
site = ()
def __new__(cls):
self = threading.local.__new__(cls)
return self.__get, self.__set
def __get(self):
"""Returns the currently processed site
XXX The returned site is not wrapped in a request.
"""
app, site_id = self.site[-1]
app = app()
return CMFSite.__of__(app.__dict__[site_id], app)
def __set(self, site):
app = aq_base(site.aq_parent)
self.site = [x for x in self.site if x[0]() is not app]
# Use weak references for automatic cleanup. In practice, this is probably
# useless, because there is no reason a thread reopen the database.
self.site.append((weakref(app, self.__del), site.id))
def __del(self, app):
self.site = [x for x in self.site if x[0] is not app]
getSite, setSite = _site()
class ERP5Site(FolderMixIn, CMFSite, CacheCookieMixin):
"""
The *only* function this class should have is to help in the setup
......@@ -213,6 +246,17 @@ class ERP5Site(FolderMixIn, CMFSite, CacheCookieMixin):
"""
return self.index_html()
def __of__(self, parent):
self = CMFSite.__of__(self, parent)
# Use a transactional variable for performance reason,
# since ERP5Site.__of__ is called quite often.
tv = getTransactionalVariable()
if 'ERP5Site.__of__' not in tv:
tv['ERP5Site.__of__'] = None
setSite(self)
synchronizeDynamicModules(self)
return self
def manage_beforeDelete(self, item, container):
# On Zope 2.8, skin is setup during Acquisition (in the .__of__() method).
# On Zope 2.12, skin is setup during __before_publishing_traverse__, which
......@@ -359,14 +403,6 @@ class ERP5Site(FolderMixIn, CMFSite, CacheCookieMixin):
# and tries to load subobjects of the portal too early
return []
security.declareProtected(Permissions.AccessContentsInformation, 'objectValues')
def objectValues(self, *args, **kw):
# When stepping in an ERP5Site from outside,
# (e.g. left hand tree frame in {zope root}/manage )
# we need to set up the site to load portal types inside each site
setSite(self)
return super(ERP5Site, self).objectValues(*args, **kw)
security.declareProtected(Permissions.AccessContentsInformation, 'searchFolder')
def searchFolder(self, **kw):
"""
......@@ -375,7 +411,6 @@ class ERP5Site(FolderMixIn, CMFSite, CacheCookieMixin):
"""
if not kw.has_key('parent_uid'):
kw['parent_uid'] = self.uid
setSite(self)
return self.portal_catalog.searchResults(**kw)
security.declareProtected(Permissions.AccessContentsInformation, 'countFolder')
......@@ -386,7 +421,6 @@ class ERP5Site(FolderMixIn, CMFSite, CacheCookieMixin):
"""
if not kw.has_key('parent_uid'):
kw['parent_uid'] = self.uid
setSite(self)
return self.portal_catalog.countResults(**kw)
# Proxy methods for security reasons
......@@ -1484,23 +1518,6 @@ class ERP5Generator(PortalGenerator):
# Return the fully wrapped object.
p = parent.this()._getOb(id)
setSite(p)
try:
sm = p.getSiteManager()
except:
# Zope 2.8, ot site manager, no DefaultTraversable, dont care
pass
else:
import zope
# XXX hackish, required to setUpERP5Core while in tests,
# could probably be better
# (for some reason calling setSite here does not allow
# the newly created site to find the global DefaultTraversable
# object)
sm.registerAdapter(zope.traversing.adapters.DefaultTraversable,
required=(zope.interface.Interface,))
erp5_sql_deferred_connection_string = erp5_sql_connection_string
p._setProperty('erp5_catalog_storage',
erp5_catalog_storage, 'string')
......
......@@ -46,7 +46,6 @@ import re
# minimal IP:Port regexp
NODE_RE = re.compile('^\d+\.\d+\.\d+\.\d+:\d+$')
from zope.site.hooks import setSite
try:
from Products.TimerService import getTimerService
except ImportError:
......@@ -211,10 +210,6 @@ class AlarmTool(BaseTool):
if not acquired:
return
try:
portal = self.getPortalObject()
setSite(portal)
# make sure our skin is set-up. On CMF 1.5 it's setup by acquisition,
# but on 2.2 it's by traversal, and our site probably wasn't traversed
# by the timerserver request, which goes into the Zope Control_Panel
......
......@@ -6,7 +6,6 @@ import sys
import inspect
from types import ModuleType
from zope.site.hooks import getSite
from Products.ERP5Type.Globals import InitializeClass
from Products.ERP5Type.Utils import setDefaultClassProperties
......@@ -54,6 +53,7 @@ def portal_type_factory(portal_type_name):
# before creating any Base Type object
type_class = "BusinessTemplate"
else:
from Products.ERP5.ERP5Site import getSite
site = getSite()
type_tool = site.portal_types
......
......@@ -70,4 +70,3 @@ from Products.ERP5Type.patches import ZopePageTemplate
from Products.ERP5Type.patches.PropertyManager import ERP5PropertyManager
from Products.ERP5Type.patches.DCWorkflow import ValidationFailed, ERP5TransitionDefinition
from Products.ERP5Type.patches.BTreeFolder2 import ERP5BTreeFolder2Base
from Products.ERP5Type.patches.getSite import getSite
from Products.ERP5Type import Globals
module_name = 'zope.site.hooks'
try:
hooks = __import__(module_name, {}, {}, module_name)
_getSite = hooks.getSite
_setSite = hooks.setSite
except ImportError:
# backwards compatibility for Zope < 2.12
import imp, sys
import zope
try:
site = zope.site
except:
sys.modules['zope.site'] = zope.site = imp.new_module('zope.site')
sys.modules[module_name] = hooks = imp.new_module(module_name)
def _getSite():
return None
def _setSite(site=None):
request = Globals.get_request()
if not (None in (site, request) or site in request.get('PARENTS', ())):
request['PARENTS'] = [site]
# patch getSite so that it works everywhere
def getSite():
site = _getSite()
if site is None:
parents = Globals.get_request()['PARENTS']
for site in parents[::-1]:
if getattr(site, 'getPortalObject', None) is not None:
break
else:
raise AttributeError("getSite() can't retrieve the site")
return site
hooks.getSite = getSite
def setSite(site=None):
_setSite(site)
if site is not None:
from Products.ERP5Type.Dynamic.portaltypeclass import synchronizeDynamicModules
synchronizeDynamicModules(site)
hooks.setSite = setSite
......@@ -49,6 +49,14 @@ def get_request():
Products.ERP5Type.Utils.get_request = get_request
Globals.get_request = get_request
try:
from zope.site.hooks import setSite
except ImportError:
# BACK: Zope 2.8. setSite is somewhere else, and we can't use it anyway
# since ERP5Site is not yet an ISite. Remove once we drop support for 2.8
def setSite(site=None):
pass
try:
import itools.zope
itools.zope.get_context = get_context
......@@ -221,8 +229,6 @@ failed_portal_installation = {}
# this is a mapping 'list of business template -> boolean
setup_done = {}
from zope.site.hooks import setSite
def _getConnectionStringDict():
"""Returns the connection strings used for this test.
"""
......
......@@ -536,6 +536,7 @@ def runUnitTestList(test_list, verbosity=1, debug=0):
import transaction
transaction.commit()
ZopeTestCase.close(app)
del app
if zeo_client_pid_list is None:
result = suite()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment