[Zope3-dev] Enhanced Workflow

Jeffrey P Shell jeffrey@cuemedia.com
Fri, 14 Dec 2001 14:18:49 -0700


On Friday, December 14, 2001, at 06:13  PM, Florent Guillaume wrote:

>>> Given the current CMF model, it is rather painful to publish an 
>>> single
>>> folder of documents or an entire folder tree at once -- each document
>>> is independent and has no relation to its parent folders.
>>
>> Good point!
>
> I'll have a proposal written up this week-end about this.
>
> Basically (this will be for Zope2, and adapt for Zope3) I propose to
> define two new interfaces, _isWorkflowManager and _isWorkflowAware.
>
> An object that is a WorkflowManager is consulted by the Workflow Tool
> one behalf of any of its children when taking workflow-related 
> decisions
> (find available actions, do action, find available workflows).
>
> An object that is WorkflowAware is directly consulted by the Workflow
> Tool for the same decisions. In both cases the object can decide to
> fallback on the standard behaviour, but can also change its state, etc.
>
> A combination of the two can pretty easily do what's proposed at 
> the top
> of this message : when a WorkflowAware ObjectManager changes state, it
> can impose the same state recursively to all its children. And if it is
> also WorkflowManager it can veto any independant state change of the
> children. Or do more complex things.

I've been debating in my head where this policy makes sense - 
should it be in the Workflow Agent, or the end object?  Coming back 
around to a task management system - I have it in my workflow 
policy that a task cannot be put in an outside state unless all of 
its subtasks (a task is a container, and based on its portal type 
may hold just other Tasks or other objects as well) are in an 
outside state (ie - Cancelled, Denied, or Completed).  I don't care 
about other workflows affecting other contained objects - an Image 
may be published or not (I've actually replaced the default 
workflow with an auto-publisher that is different than the default 
CMF flow).

Currently, when you go to change the state on a Task, it does a 
catalog query to find all subtasks that are not in an outside 
state.  One still has to go to them each manually and change their 
state, but I'm going to put the ability to affect all of them into 
either the workflow agent itself, or at least into the skin.  I 
don't think that a Task itself should have to worry about this at 
all.

I really like having all of the workflow related stuff *away* from 
the Task.  I don't think that so-called "content objects" should 
have any workflow related code in them if they can help it (one 
could argue that part of a Task's interface is its status, and that 
the workflow defines that status.  But I would like the idea of 
using tasks in a workflow-free system where status setting followed 
no real rules at all).

There's nothing stopping an object being consulted by a workflow 
process for certain decisions.  Granted, I haven't dealt too much 
with DCWorkflow based process definitions - but in writing a Python 
based one the object is passed in as an argument to almost all of 
the methods specified in the interface a workflow agent has to 
support, allowing the workflow to do its query.  I *imagine* you 
could do this with scripts in DCWorkflow.  For example - if a task 
is of a certain tasktype, such as 'software bug', it has an extra 
'Testing' state that it can go into:

     elif task_status == 'In Progress':
         if content.TaskType() in self.testable_types:
            append_action(('Testing', 'set_testing'))
     ...
     elif task_status not in testable_states and \
          ob.TaskType() not in self.testable_types:
         raise Unauthorized, 'Not in a testing state'

So, the target object can be queried.  This is, in fact, how I also 
test the sub-tasks:

     def notifyBefore(self, ob, action):
         Catalog = getToolByName(self, 'portal_catalog')
         to_outer = ('set_cancelled', 'set_denied', 'set_done')
         if action in to_outer:
             task_status = list(self._innerStates + self._freshStates)
             path = '/'.join(ob.getPhysicalPath())
             waiting = Catalog(path=path, task_status=task_status)
             if waiting:
                 raise WorkflowException('There are subitems needing 
review')

So, the current workflow architecture does support this.  I could 
change this 'notifyBefore' to send the current action to all of the 
found subtasks if I wanted to change the policy to do that.  I just 
don't know how to do this in DCWorkflow since I haven't really used 
it.

In summary - I believe that any policies about dealing with 
associated objects should be handled by the workflow agents 
themselves.  Why?  Because one might want to install a workflow 
about publishing that is really screwed-down about publishing 
associated objects ("I will not automatically publish all of these 
connected things.  You (the user) are expected to review them 
yourself!"), or one might want to install a lax one ("Alright.  
I'll publish all of these images I reference too. Fine by me!").  
If that policy is put into the content objects themselves in any 
way, you cut down on your ability to change policy later.

At most, I'd like 'WorkflowAware' and 'WorkflowManager' to be some 
sort of decorator/adapter/whatever that wraps around the object 
dynamically to set these policies.

In my opinion anyways.