Commit ad42d728 authored by Florent Guillaume's avatar Florent Guillaume

Zope now sends Zope 3 events when objects are added or removed from

standard containers. manage_afterAdd, manage_beforeDelete and
manage_afterClone are now deprecated. See
lib/python/Products/Five/tests/event.txt for details.

This requires Five 1.3 (included in Zope 2.9).
parent 7a3b9de0
...@@ -26,6 +26,11 @@ Zope Changes ...@@ -26,6 +26,11 @@ Zope Changes
Features added Features added
- Zope now sends Zope 3 events when objects are added or removed
from standard containers. manage_afterAdd, manage_beforeDelete
and manage_afterClone are now deprecated. See
lib/python/Products/Five/tests/event.txt for details.
- Zope now utilizes ZODB 3.6. It had previously used - Zope now utilizes ZODB 3.6. It had previously used
ZODB 3.4. As a result, the DBTab package was removed, as ZODB 3.4. As a result, the DBTab package was removed, as
ZODB 3.6 has multidatabase support that makes DBTab ZODB 3.6 has multidatabase support that makes DBTab
......
...@@ -459,6 +459,10 @@ class AppInitializer: ...@@ -459,6 +459,10 @@ class AppInitializer:
from Products.Sessions.BrowserIdManager import BrowserIdManager from Products.Sessions.BrowserIdManager import BrowserIdManager
bid = BrowserIdManager('browser_id_manager', 'Browser Id Manager') bid = BrowserIdManager('browser_id_manager', 'Browser Id Manager')
app._setObject('browser_id_manager', bid) app._setObject('browser_id_manager', bid)
# FIXME explicitely call manage_afterAdd, as sometimes
# events are initialized too late
browser_id_manager = app.browser_id_manager
browser_id_manager.manage_afterAdd(browser_id_manager, app)
app._setInitializerFlag('browser_id_manager') app._setInitializerFlag('browser_id_manager')
self.commit('Added browser_id_manager') self.commit('Added browser_id_manager')
...@@ -475,6 +479,10 @@ class AppInitializer: ...@@ -475,6 +479,10 @@ class AppInitializer:
path='/temp_folder/session_data', path='/temp_folder/session_data',
requestName='SESSION') requestName='SESSION')
app._setObject('session_data_manager', sdm) app._setObject('session_data_manager', sdm)
# FIXME explicitely call manage_afterAdd, as sometimes
# events are initialized too late
session_data_manager = app.session_data_manager
session_data_manager.manage_afterAdd(session_data_manager, app)
app._setInitializerFlag('session_data_manager') app._setInitializerFlag('session_data_manager')
self.commit('Added session_data_manager') self.commit('Added session_data_manager')
...@@ -523,6 +531,10 @@ class AppInitializer: ...@@ -523,6 +531,10 @@ class AppInitializer:
from Products.SiteErrorLog.SiteErrorLog import SiteErrorLog from Products.SiteErrorLog.SiteErrorLog import SiteErrorLog
error_log = SiteErrorLog() error_log = SiteErrorLog()
app._setObject('error_log', error_log) app._setObject('error_log', error_log)
# FIXME explicitely call manage_afterAdd, as sometimes
# events are initialized too late
error_log = app.error_log
error_log.manage_afterAdd(error_log, app)
app._setInitializerFlag('error_log') app._setInitializerFlag('error_log')
self.commit('Added site error_log at /error_log') self.commit('Added site error_log at /error_log')
......
This diff is collapsed.
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
$Id$ $Id$
""" """
import warnings
import marshal import marshal
import sys, fnmatch, copy, os, re import sys, fnmatch, copy, os, re
from cgi import escape from cgi import escape
...@@ -42,6 +43,11 @@ from zope.interface import implements ...@@ -42,6 +43,11 @@ from zope.interface import implements
import CopySupport import CopySupport
from interfaces import IObjectManager from interfaces import IObjectManager
from Traversable import Traversable from Traversable import Traversable
from zope.event import notify
from zope.app.container.contained import ObjectAddedEvent
from zope.app.container.contained import ObjectRemovedEvent
from Products.Five.event import ObjectWillBeAddedEvent
from Products.Five.event import ObjectWillBeRemovedEvent
# the name BadRequestException is relied upon by 3rd-party code # the name BadRequestException is relied upon by 3rd-party code
...@@ -266,11 +272,20 @@ class ObjectManager( ...@@ -266,11 +272,20 @@ class ObjectManager(
raise AttributeError, id raise AttributeError, id
return default return default
def _setObject(self, id, object, roles=None, user=None, set_owner=1): def _setObject(self, id, object, roles=None, user=None, set_owner=1,
v=self._checkId(id) suppress_events=False):
if v is not None: id=v """Set an object into this container.
try: t=object.meta_type
except: t=None Also sends IObjectWillBeAddedEvent and IObjectAddedEvent.
"""
# Done here to avoid circular imports
from Products.Five.subscribers import maybeCallDeprecated
ob = object # better name, keep original function signature
v = self._checkId(id)
if v is not None:
id = v
t = getattr(ob, 'meta_type', None)
# If an object by the given id already exists, remove it. # If an object by the given id already exists, remove it.
for object_info in self._objects: for object_info in self._objects:
...@@ -278,78 +293,78 @@ class ObjectManager( ...@@ -278,78 +293,78 @@ class ObjectManager(
self._delObject(id) self._delObject(id)
break break
self._objects=self._objects+({'id':id,'meta_type':t},) if not suppress_events:
self._setOb(id,object) notify(ObjectWillBeAddedEvent(ob, self, id))
object=self._getOb(id)
self._objects = self._objects + ({'id': id, 'meta_type': t},)
self._setOb(id, ob)
ob = self._getOb(id)
if set_owner: if set_owner:
object.manage_fixupOwnershipAfterAdd() # TODO: eventify manage_fixupOwnershipAfterAdd
# This will be called for a copy/clone, or a normal _setObject.
ob.manage_fixupOwnershipAfterAdd()
# Try to give user the local role "Owner", but only if # Try to give user the local role "Owner", but only if
# no local roles have been set on the object yet. # no local roles have been set on the object yet.
if hasattr(object, '__ac_local_roles__'): if getattr(ob, '__ac_local_roles__', _marker) is None:
if object.__ac_local_roles__ is None: user = getSecurityManager().getUser()
user=getSecurityManager().getUser() if user is not None:
if user is not None: userid = user.getId()
userid=user.getId() if userid is not None:
if userid is not None: ob.manage_setLocalRoles(userid, ['Owner'])
object.manage_setLocalRoles(userid, ['Owner'])
if not suppress_events:
object.manage_afterAdd(object, self) notify(ObjectAddedEvent(ob, self, id))
maybeCallDeprecated('manage_afterAdd', ob, self)
return id return id
def manage_afterAdd(self, item, container): def manage_afterAdd(self, item, container):
for object in self.objectValues(): # Don't do recursion anymore, a subscriber does that.
try: s=object._p_changed warnings.warn(
except: s=0 "%s.manage_afterAdd is deprecated and will be removed in "
if hasattr(aq_base(object), 'manage_afterAdd'): "Zope 2.11, you should use an IObjectAddedEvent "
object.manage_afterAdd(item, container) "subscriber instead." % self.__class__.__name__,
if s is None: object._p_deactivate() DeprecationWarning, stacklevel=2)
manage_afterAdd.__five_method__ = True
def manage_afterClone(self, item): def manage_afterClone(self, item):
for object in self.objectValues(): # Don't do recursion anymore, a subscriber does that.
try: s=object._p_changed warnings.warn(
except: s=0 "%s.manage_afterClone is deprecated and will be removed in "
if hasattr(aq_base(object), 'manage_afterClone'): "Zope 2.11, you should use an IFiveObjectClonedEvent "
object.manage_afterClone(item) "subscriber instead." % self.__class__.__name__,
if s is None: object._p_deactivate() DeprecationWarning, stacklevel=2)
manage_afterClone.__five_method__ = True
def manage_beforeDelete(self, item, container): def manage_beforeDelete(self, item, container):
for object in self.objectValues(): # Don't do recursion anymore, a subscriber does that.
try: s=object._p_changed warnings.warn(
except: s=0 "%s.manage_beforeDelete is deprecated and will be removed in "
try: "Zope 2.11, you should use an IObjectWillBeRemovedEvent "
if hasattr(aq_base(object), 'manage_beforeDelete'): "subscriber instead." % self.__class__.__name__,
object.manage_beforeDelete(item, container) DeprecationWarning, stacklevel=2)
except BeforeDeleteException, ob: manage_beforeDelete.__five_method__ = True
raise
except ConflictError: def _delObject(self, id, dp=1, suppress_events=False):
raise """Delete an object from this container.
except:
LOG('Zope',ERROR,'manage_beforeDelete() threw', Also sends IObjectWillBeRemovedEvent and IObjectRemovedEvent.
error=sys.exc_info()) """
# In debug mode when non-Manager, let exceptions propagate. # Done here to avoid circular imports
if getConfiguration().debug_mode: from Products.Five.subscribers import maybeCallDeprecated
if not getSecurityManager().getUser().has_role('Manager'):
raise ob = self._getOb(id)
if s is None: object._p_deactivate()
maybeCallDeprecated('manage_beforeDelete', ob, self)
def _delObject(self, id, dp=1):
object=self._getOb(id) if not suppress_events:
try: notify(ObjectWillBeRemovedEvent(ob, self, id))
object.manage_beforeDelete(object, self)
except BeforeDeleteException, ob: self._objects = tuple([i for i in self._objects
raise if i['id'] != id])
except ConflictError:
raise
except:
LOG('Zope', ERROR, '_delObject() threw',
error=sys.exc_info())
# In debug mode when non-Manager, let exceptions propagate.
if getConfiguration().debug_mode:
if not getSecurityManager().getUser().has_role('Manager'):
raise
self._objects=tuple(filter(lambda i,n=id: i['id']!=n, self._objects))
self._delOb(id) self._delOb(id)
# Indicate to the object that it has been deleted. This is # Indicate to the object that it has been deleted. This is
...@@ -357,8 +372,13 @@ class ObjectManager( ...@@ -357,8 +372,13 @@ class ObjectManager(
# tolerate failure here because the object being deleted could # tolerate failure here because the object being deleted could
# be a Broken object, and it is not possible to set attributes # be a Broken object, and it is not possible to set attributes
# on Broken objects. # on Broken objects.
try: object._v__object_deleted__ = 1 try:
except: pass ob._v__object_deleted__ = 1
except:
pass
if not suppress_events:
notify(ObjectRemovedEvent(ob, self, id))
def objectIds(self, spec=None): def objectIds(self, spec=None):
# Returns a list of subobject ids of the current object. # Returns a list of subobject ids of the current object.
......
...@@ -30,7 +30,7 @@ from IOrderSupport import IOrderedContainer as z2IOrderedContainer ...@@ -30,7 +30,7 @@ from IOrderSupport import IOrderedContainer as z2IOrderedContainer
from ObjectManager import ObjectManager from ObjectManager import ObjectManager
class OrderSupport: class OrderSupport(object):
""" Ordered container mixin class. """ Ordered container mixin class.
...@@ -251,13 +251,12 @@ class OrderSupport: ...@@ -251,13 +251,12 @@ class OrderSupport:
# Override Inherited Method of ObjectManager Subclass # Override Inherited Method of ObjectManager Subclass
# #
_old_manage_renameObject = ObjectManager.inheritedAttribute(
'manage_renameObject')
def manage_renameObject(self, id, new_id, REQUEST=None): def manage_renameObject(self, id, new_id, REQUEST=None):
""" Rename a particular sub-object without changing its position. """ Rename a particular sub-object without changing its position.
""" """
old_position = self.getObjectPosition(id) old_position = self.getObjectPosition(id)
result = self._old_manage_renameObject(id, new_id, REQUEST) result = super(OrderSupport, self).manage_renameObject(id, new_id,
REQUEST)
self.moveObjectToPosition(new_id, old_position) self.moveObjectToPosition(new_id, old_position)
return result return result
......
...@@ -20,6 +20,7 @@ item types. ...@@ -20,6 +20,7 @@ item types.
$Id$ $Id$
""" """
import warnings
import marshal, re, sys, time import marshal, re, sys, time
import AccessControl.Role, AccessControl.Owned, App.Common import AccessControl.Role, AccessControl.Owned, App.Common
...@@ -60,13 +61,28 @@ class Item(Base, Resource, CopySource, App.Management.Tabs, Traversable, ...@@ -60,13 +61,28 @@ class Item(Base, Resource, CopySource, App.Management.Tabs, Traversable,
isTopLevelPrincipiaApplicationObject=0 isTopLevelPrincipiaApplicationObject=0
def manage_afterAdd(self, item, container): def manage_afterAdd(self, item, container):
pass warnings.warn(
"%s.manage_afterAdd is deprecated and will be removed in "
"Zope 2.11, you should use an IObjectAddedEvent "
"subscriber instead." % self.__class__.__name__,
DeprecationWarning, stacklevel=2)
manage_afterAdd.__five_method__ = True
def manage_beforeDelete(self, item, container): def manage_beforeDelete(self, item, container):
pass warnings.warn(
"%s.manage_beforeDelete is deprecated and will be removed in "
"Zope 2.11, you should use an IObjectWillBeRemovedEvent "
"subscriber instead." % self.__class__.__name__,
DeprecationWarning, stacklevel=2)
manage_beforeDelete.__five_method__ = True
def manage_afterClone(self, item): def manage_afterClone(self, item):
pass warnings.warn(
"%s.manage_afterClone is deprecated and will be removed in "
"Zope 2.11, you should use an IFiveObjectClonedEvent "
"subscriber instead." % self.__class__.__name__,
DeprecationWarning, stacklevel=2)
manage_afterClone.__five_method__ = True
# Direct use of the 'id' attribute is deprecated - use getId() # Direct use of the 'id' attribute is deprecated - use getId()
id='' id=''
......
...@@ -37,6 +37,11 @@ from AccessControl.Permissions import access_contents_information, \ ...@@ -37,6 +37,11 @@ from AccessControl.Permissions import access_contents_information, \
view_management_screens view_management_screens
from zLOG import LOG, INFO, ERROR, WARNING from zLOG import LOG, INFO, ERROR, WARNING
from Products.ZCatalog.Lazy import LazyMap from Products.ZCatalog.Lazy import LazyMap
from zope.event import notify
from zope.app.container.contained import ObjectAddedEvent
from zope.app.container.contained import ObjectRemovedEvent
from Products.Five.event import ObjectWillBeAddedEvent
from Products.Five.event import ObjectWillBeRemovedEvent
manage_addBTreeFolderForm = DTMLFile('folderAdd', globals()) manage_addBTreeFolderForm = DTMLFile('folderAdd', globals())
...@@ -404,47 +409,64 @@ class BTreeFolder2Base (Persistent): ...@@ -404,47 +409,64 @@ class BTreeFolder2Base (Persistent):
'it is already in use.' % id) 'it is already in use.' % id)
def _setObject(self, id, object, roles=None, user=None, set_owner=1): def _setObject(self, id, object, roles=None, user=None, set_owner=1,
v=self._checkId(id) suppress_events=False):
if v is not None: id=v # Done here to avoid circular imports
from Products.Five.subscribers import maybeCallDeprecated
ob = object # better name, keep original function signature
v = self._checkId(id)
if v is not None:
id = v
# If an object by the given id already exists, remove it. # If an object by the given id already exists, remove it.
if self.has_key(id): if self.has_key(id):
self._delObject(id) self._delObject(id)
self._setOb(id, object) if not suppress_events:
object = self._getOb(id) notify(ObjectWillBeAddedEvent(ob, self, id))
self._setOb(id, ob)
ob = self._getOb(id)
if set_owner: if set_owner:
object.manage_fixupOwnershipAfterAdd() # TODO: eventify manage_fixupOwnershipAfterAdd
# This will be called for a copy/clone, or a normal _setObject.
ob.manage_fixupOwnershipAfterAdd()
# Try to give user the local role "Owner", but only if # Try to give user the local role "Owner", but only if
# no local roles have been set on the object yet. # no local roles have been set on the object yet.
if hasattr(object, '__ac_local_roles__'): if getattr(ob, '__ac_local_roles__', _marker) is None:
if object.__ac_local_roles__ is None: user = getSecurityManager().getUser()
user=getSecurityManager().getUser() if user is not None:
if user is not None: userid = user.getId()
userid=user.getId() if userid is not None:
if userid is not None: ob.manage_setLocalRoles(userid, ['Owner'])
object.manage_setLocalRoles(userid, ['Owner'])
if not suppress_events:
object.manage_afterAdd(object, self) notify(ObjectAddedEvent(ob, self, id))
maybeCallDeprecated('manage_afterAdd', ob, self)
return id return id
def _delObject(self, id, dp=1): def _delObject(self, id, dp=1, suppress_events=False):
object = self._getOb(id) # Done here to avoid circular imports
try: from Products.Five.subscribers import maybeCallDeprecated
object.manage_beforeDelete(object, self)
except BeforeDeleteException, ob: ob = self._getOb(id)
raise
except ConflictError: maybeCallDeprecated('manage_beforeDelete', ob, self)
raise
except: if not suppress_events:
LOG('Zope', ERROR, 'manage_beforeDelete() threw', notify(ObjectWillBeRemovedEvent(ob, self, id))
error=sys.exc_info())
self._delOb(id) self._delOb(id)
if not suppress_events:
notify(ObjectRemovedEvent(ob, self, id))
# Aliases for mapping-like access. # Aliases for mapping-like access.
__len__ = objectCount __len__ = objectCount
......
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