[Erp5-report] r42257 jm - in /erp5/trunk/products/CMFActivity: ./ Activity/ tests/

nobody at svn.erp5.org nobody at svn.erp5.org
Wed Jan 12 12:39:10 CET 2011


Author: jm
Date: Wed Jan 12 12:39:10 2011
New Revision: 42257

URL: http://svn.erp5.org?rev=42257&view=rev
Log:
CMFActivity: allow activating an object from a before commit hook

This is required for workflow scripts that are run at the end of the transaction.

Modified:
    erp5/trunk/products/CMFActivity/Activity/Queue.py
    erp5/trunk/products/CMFActivity/ActivityBuffer.py
    erp5/trunk/products/CMFActivity/ActivityTool.py
    erp5/trunk/products/CMFActivity/tests/testCMFActivity.py

Modified: erp5/trunk/products/CMFActivity/Activity/Queue.py
URL: http://svn.erp5.org/erp5/trunk/products/CMFActivity/Activity/Queue.py?rev=42257&r1=42256&r2=42257&view=diff
==============================================================================
--- erp5/trunk/products/CMFActivity/Activity/Queue.py [utf8] (original)
+++ erp5/trunk/products/CMFActivity/Activity/Queue.py [utf8] Wed Jan 12 12:39:10 2011
@@ -273,7 +273,7 @@ class Queue:
     return 0
 
   # Transaction Management
-  def prepareQueueMessage(self, activity_tool, m):
+  def prepareQueueMessageList(self, activity_tool, message_list):
     # Called to prepare transaction commit for queued messages
     pass
 

Modified: erp5/trunk/products/CMFActivity/ActivityBuffer.py
URL: http://svn.erp5.org/erp5/trunk/products/CMFActivity/ActivityBuffer.py?rev=42257&r1=42256&r2=42257&view=diff
==============================================================================
--- erp5/trunk/products/CMFActivity/ActivityBuffer.py [utf8] (original)
+++ erp5/trunk/products/CMFActivity/ActivityBuffer.py [utf8] Wed Jan 12 12:39:10 2011
@@ -33,108 +33,81 @@ class ActivityBuffer(TM):
 
   _p_oid=_p_changed=_registered=None
 
-  def __init__(self, activity_tool=None):
-    self.requires_prepare = 0
-
-  def _getBuffer(self):
-    buffer = self
-    # Create attributes only if they are not present.
-    if not hasattr(buffer, 'queued_activity'):
-      buffer.queued_activity = []
-      buffer.flushed_activity = []
-      buffer.message_list_dict = {}
-      buffer.uid_set_dict = {}
-    return buffer
-
-  def _clearBuffer(self):
-    buffer = self._getBuffer()
-    del buffer.queued_activity[:]
-    del buffer.flushed_activity[:]
-    buffer.message_list_dict.clear()
-    buffer.uid_set_dict.clear()
+  def __init__(self):
+    self.queued_activity = []
+    self.flushed_activity = []
+    self.message_list_dict = {}
+    self.uid_set_dict = {}
+
+  def _clear(self):
+    del self.queued_activity[:]
+    del self.flushed_activity[:]
+    self.message_list_dict.clear()
+    self.uid_set_dict.clear()
+    self.activity_tool = None
 
   def getMessageList(self, activity):
-    buffer = self._getBuffer()
-    return buffer.message_list_dict.setdefault(activity, []) 
+    return self.message_list_dict.setdefault(activity, [])
 
   def getUidSet(self, activity):
-    buffer = self._getBuffer()
-    return buffer.uid_set_dict.setdefault(activity, set())
+    return self.uid_set_dict.setdefault(activity, set())
 
   def _register(self, activity_tool):
     if not self._registered:
-      self._beginAndHook(activity_tool)
+      self.activity_tool = activity_tool
+      self._activity_tool_path = activity_tool.getPhysicalPath()
       TM._register(self)
+      self._prepare_args = 0, 0
+    if self._prepare_args:
+      transaction.get().addBeforeCommitHook(self._prepare, self._prepare_args)
+      self._prepare_args = None
 
   # Keeps a list of messages to add and remove
   # at end of transaction
-  def _beginAndHook(self, activity_tool):
+  def _begin(self):
     # LOG('ActivityBuffer', 0, '_begin %r' % (self,))
     from ActivityTool import activity_dict
-    self.requires_prepare = 1
     try:
-
       # Reset registration for each transaction.
       for activity in activity_dict.itervalues():
         activity.registerActivityBuffer(self)
-
-      # Notice: The operation below cannot fail silently, or we get errors late
-      # in the transaction that are very hard to understand.
-      transaction.get().addBeforeCommitHook(self.tpc_prepare,
-                                            (transaction,),
-                                            dict(activity_tool=activity_tool))
     except:
       LOG('ActivityBuffer', ERROR, "exception during _begin",
           error=sys.exc_info())
       raise
 
-  def _finish(self, *ignored):
+  def _finish(self):
     # LOG('ActivityBuffer', 0, '_finish %r' % (self,))
     try:
       try:
         # Try to push / delete all messages
-        buffer = self._getBuffer()
-        for (activity, message) in buffer.flushed_activity:
+        for activity, message in self.flushed_activity:
           activity.finishDeleteMessage(self._activity_tool_path, message)
-        for (activity, message) in buffer.queued_activity:
+        for activity, message in self.queued_activity:
           activity.finishQueueMessage(self._activity_tool_path, message)
       except:
         LOG('ActivityBuffer', ERROR, "exception during _finish",
             error=sys.exc_info())
         raise
     finally:
-      self._clearBuffer()
-
-  def _abort(self, *ignored):
-    self._clearBuffer()
-
-  def tpc_prepare(self, transaction, sub=None, activity_tool=None):
-    assert activity_tool is not None
-    self._activity_tool_path = activity_tool.getPhysicalPath()
-    # Do nothing if it is a subtransaction
-    if sub is not None:
-      return
+      self._clear()
 
-    if not self.requires_prepare:
-      return
+  _abort = _clear
 
-    self.requires_prepare = 0
+  def _prepare(self, flushed, queued):
     try:
+      activity_tool = self.activity_tool
       # Try to push / delete all messages
-      buffer = self._getBuffer()
-      for (activity, message) in buffer.flushed_activity:
+      for activity, message in self.flushed_activity[flushed:]:
         activity.prepareDeleteMessage(activity_tool, message)
       activity_dict = {}
-      for (activity, message) in buffer.queued_activity:
+      for activity, message in self.queued_activity[queued:]:
         activity_dict.setdefault(activity, []).append(message)
       for activity, message_list in activity_dict.iteritems():
-        if hasattr(activity, 'prepareQueueMessageList'):
-          activity.prepareQueueMessageList(activity_tool, message_list)
-        else:
-          for message in message_list:
-            activity.prepareQueueMessage(activity_tool, message)
+        activity.prepareQueueMessageList(activity_tool, message_list)
+      self._prepare_args = len(self.flushed_activity), len(self.queued_activity)
     except:
-      LOG('ActivityBuffer', ERROR, "exception during tpc_prepare",
+      LOG('ActivityBuffer', ERROR, "exception during _prepare",
           error=sys.exc_info())
       raise
 
@@ -143,16 +116,14 @@ class ActivityBuffer(TM):
     # Activity is called to prevent queuing some messages (useful for example
     # to prevent reindexing objects multiple times)
     if not activity.isMessageRegistered(self, activity_tool, message):
-      buffer = self._getBuffer()
-      buffer.queued_activity.append((activity, message))
+      self.queued_activity.append((activity, message))
       # We register queued messages so that we can
       # unregister them
       activity.registerMessage(self, activity_tool, message)
 
   def deferredDeleteMessage(self, activity_tool, activity, message):
     self._register(activity_tool)
-    buffer = self._getBuffer()
-    buffer.flushed_activity.append((activity, message))
+    self.flushed_activity.append((activity, message))
 
   def sortKey(self, *ignored):
     """Activities must be finished before databases commit transactions."""

Modified: erp5/trunk/products/CMFActivity/ActivityTool.py
URL: http://svn.erp5.org/erp5/trunk/products/CMFActivity/ActivityTool.py?rev=42257&r1=42256&r2=42257&view=diff
==============================================================================
--- erp5/trunk/products/CMFActivity/ActivityTool.py [utf8] (original)
+++ erp5/trunk/products/CMFActivity/ActivityTool.py [utf8] Wed Jan 12 12:39:10 2011
@@ -1041,14 +1041,15 @@ class ActivityTool (Folder, UniqueObject
       finally:
         global_activity_buffer_lock.release()
       thread_activity_buffer = global_activity_buffer[my_instance_key]
-      if my_thread_key not in thread_activity_buffer:
+      try:
+        return thread_activity_buffer[my_thread_key]
+      except KeyError:
         if create_if_not_found:
-          buffer = ActivityBuffer(activity_tool=self)
+          buffer = ActivityBuffer()
         else:
           buffer = None
         thread_activity_buffer[my_thread_key] = buffer
-      activity_buffer = thread_activity_buffer[my_thread_key]
-      return activity_buffer
+        return buffer
 
     security.declarePrivate('activateObject')
     def activateObject(self, object, activity, active_process, **kw):

Modified: erp5/trunk/products/CMFActivity/tests/testCMFActivity.py
URL: http://svn.erp5.org/erp5/trunk/products/CMFActivity/tests/testCMFActivity.py?rev=42257&r1=42256&r2=42257&view=diff
==============================================================================
--- erp5/trunk/products/CMFActivity/tests/testCMFActivity.py [utf8] (original)
+++ erp5/trunk/products/CMFActivity/tests/testCMFActivity.py [utf8] Wed Jan 12 12:39:10 2011
@@ -3832,6 +3832,19 @@ class TestCMFActivity(ERP5TypeTestCase, 
     finally:
       del activity_tool.__class__.doSomething
 
+  def test_126_beforeCommitHook(self):
+    """
+    Check it is possible to activate an object from a before commit hook
+    """
+    def doSomething(person):
+      person.activate(activity='SQLDict')._setFirstName('John')
+      person.activate(activity='SQLQueue')._setLastName('Smith')
+    person = self.portal.person_module.newContent()
+    transaction.get().addBeforeCommitHook(doSomething, (person,))
+    transaction.commit()
+    self.tic()
+    self.assertEqual(person.getTitle(), 'John Smith')
+
   def test_connection_migration(self):
     """
     Make sure the cmf_activity_sql_connection is automatically migrated from



More information about the Erp5-report mailing list