[CMF-checkins] CVS: CMF - PortalContent.py:1.12 WorkflowCore.py:1.5 WorkflowTool.py:1.7 __init__.py:1.5

shane@digicool.com shane@digicool.com
Tue, 22 May 2001 16:33:43 -0400 (EDT)


Update of /cvs-repository/CMF/CMFCore
In directory korak.digicool.com:/tmp/cvs-serv7982

Modified Files:
	PortalContent.py WorkflowCore.py WorkflowTool.py __init__.py 
Log Message:
- Refined the concept of workflow methods by allowing workflows to
  manage the invocation of workflow methods.

- Removed the necessity of invoking afterCreate() by putting the logic
  in PortalContent.manage_afterAdd() instead.  Also reduces catalog
  hits.

- Fixed a bug that made workflow type registration act strangely.

- Added WorkflowTool._invokeWithNotification() to streamline the
  workflow event notification mechanism.



--- Updated File PortalContent.py in package CMF --
--- PortalContent.py	2001/05/11 04:34:28	1.11
+++ PortalContent.py	2001/05/22 20:33:42	1.12
@@ -159,8 +159,11 @@
             catalog.reindexObject(self)
         
     def manage_afterAdd(self, item, container):
-        "Add self to the catalog."
+        "Add self to the workflow and catalog."
         if aq_base(item) is aq_base(self):
+            wf = getToolByName(self, 'portal_workflow', None)
+            if wf is not None:
+                wf.notifyCreated(self)
             self.indexObject()
 
     def manage_beforeDelete(self, item, container):

--- Updated File WorkflowCore.py in package CMF --
--- WorkflowCore.py	2001/05/07 15:27:07	1.4
+++ WorkflowCore.py	2001/05/22 20:33:42	1.5
@@ -99,48 +99,36 @@
     '''
 
 
-class WorkflowAction (Method):
+class WorkflowMethod (Method):
     '''
     Wraps a method to workflow-enable it.
     '''
     _need__name__=1
 
-    def __init__(self, method, action=None, reindex=1):
+    def __init__(self, method, id=None, reindex=1):
         self._m = method
-        if action is None:
-            action = method.__name__
-        self._a = action
-        self._reindex = reindex
+        if id is None:
+            id = method.__name__
+        self._id = id
+        # reindex ignored since workflows now perform the reindexing.
 
     def __call__(self, instance, *args, **kw):
         '''
         Invokes the method.
         '''
         wf = getToolByName(instance, 'portal_workflow', None)
-        if wf is None:
+        if wf is None or not hasattr(wf, 'wrapWorkflowMethod'):
             # No workflow found.
-            return apply(self._m, (instance,) + args, kw)
+            res = apply(self._m, (instance,) + args, kw)
         else:
-            action = self._a
-            wf.notifyBefore(instance, action)  # Can throw an exception.
-            try:
-                res = apply(self._m, (instance,) + args, kw)
-            except:
-                wf.notifyException(instance, action, sys.exc_info())
-                raise
-            else:
-                wf.notifySuccess(instance, action, res)
-                if self._reindex:
-                    catalog = getToolByName(instance, 'portal_catalog', None)
-                    if catalog is not None:
-                        catalog.reindexObject(instance)
-                return res
+            res = wf.wrapWorkflowMethod(instance, self._id, self._m,
+                                        (instance,) + args, kw)
+        return res
 
+# Backward compatibility.
+WorkflowAction = WorkflowMethod
 
+
 def afterCreate(ob):
-    wf = getToolByName(ob, 'portal_workflow', None)
-    if wf is not None:
-        wf.notifyCreated(ob)
-        catalog = getToolByName(ob, 'portal_catalog', None)
-        if catalog is not None:
-            catalog.reindexObject(ob)
+    # This functionality is now in PortalContent.py.
+    pass

--- Updated File WorkflowTool.py in package CMF --
--- WorkflowTool.py	2001/05/11 03:38:28	1.6
+++ WorkflowTool.py	2001/05/22 20:33:42	1.7
@@ -376,6 +376,30 @@
                         actions.extend(a)
         return actions
 
+    def _invokeWithNotification(self, wfs, ob, action, func, args, kw):
+        '''
+        Private utility method.
+        '''
+        for w in wfs:
+            w.notifyBefore(ob, action)
+        try:
+            res = apply(func, args, kw)
+        except:
+            exc = sys.exc_info()
+            try:
+                for w in wfs:
+                    w.notifyException(ob, action, exc)
+                raise exc[0], exc[1], exc[2]
+            finally:
+                exc = None
+        else:
+            for w in wfs:
+                w.notifySuccess(ob, action, res)
+            catalog = getToolByName(ob, 'portal_catalog', None)
+            if catalog is not None:
+                catalog.reindexObject(ob)
+            return res
+
     security.declarePublic('doActionFor')
     def doActionFor(self, ob, action, wf_id=None, *args, **kw):
         '''
@@ -383,9 +407,11 @@
         Allows the user to request a workflow action.  The workflow object
         must perform its own security checks.
         '''
+        wfs = self.getWorkflowsFor(ob)
+        if wfs is None:
+            wfs = ()
         if wf_id is None:
-            wfs = self.getWorkflowsFor(ob)
-            if wfs is None:
+            if not wfs:
                 raise WorkflowException('No workflows found.')
             found = 0
             for wf in wfs:
@@ -400,7 +426,31 @@
             if wf is None:
                 raise WorkflowException(
                     'Requested workflow definition not found.')
-        return apply(wf.doActionFor, (ob, action) + args, kw)
+        return self._invokeWithNotification(
+            wfs, ob, action, wf.doActionFor, (ob, action) + args, kw)
+
+    security.declarePrivate('wrapWorkflowMethod')
+    def wrapWorkflowMethod(self, ob, method_id, func, args, kw):
+        '''
+        To be invoked only by WorkflowCore.
+        Allows a workflow definition to wrap a WorkflowMethod.
+        '''
+        wf = None
+        wfs = self.getWorkflowsFor(ob)
+        if wfs:
+            for w in wfs:
+                if (hasattr(w, 'isWorkflowMethodSupported')
+                    and w.isWorkflowMethodSupported(ob, method_id)):
+                    wf = w
+                    break
+        else:
+            wfs = ()
+        if wf is None:
+            # No workflow wraps this method.
+            return apply(func, args, kw)
+        return self._invokeWithNotification(
+            wfs, ob, method_id, wf.wrapWorkflowMethod,
+            (ob, method_id, func, args, kw), {})
 
     security.declarePublic('getInfoFor')
     def getInfoFor(self, ob, name, default=_marker, wf_id=None, *args, **kw):
@@ -531,4 +581,5 @@
 def addWorkflowClass(klass):
     # klass is expected to have id, title, and meta_type attributes.
     # Its constructor should take one argument, id.
-    _workflow_classes[klass.meta_type] = klass
+    id = getattr(klass, 'id', None) or klass.meta_type
+    _workflow_classes[id] = klass

--- Updated File __init__.py in package CMF --
--- __init__.py	2001/04/07 22:59:53	1.4
+++ __init__.py	2001/05/22 20:33:42	1.5
@@ -176,3 +176,4 @@
                      , extra_constructors=(
                            PortalFolder.manage_addPortalFolder, )
                      ).initialize( context )
+