thanks a lot for sharing your experiences.
As it happens I'm right now implementing workflow for a customer.
I have no knowledge about OSWorkflow (or any other commercial or non-commercial workflow engine) and having looked at Lenya's workflow package I couldn't quite get how to use it in my context (I would be grateful if Lenya people are listening and jumping into this discussion). However while implementing I quickly discovered I came up with with similar terms (what surprise :-)
It's interesting that you connected workflow directly at the repository (backend) level, which appears right to do so at first. But I believe we should try to do it at the "Cocoon level". TBH currently I'm only interested to do it at the Cocoon level since this would allow me to use it in different "Cocoon contextes". Whether that should read "Cocoon repository level" instead of "Cocoon level" I'm not sure since there might be other objects (like simple records in a SQL table) to be attached to workflow.
But to have a common ground (and terminology) I just talk about (Cocoon's) repository and documents (being resources or objects having workflow attached).
Our customer's repository is also a WebDAV repository and the current workflow state is captured as a WebDAV property of the document.
If the Repository interface within the repository block would be extended with get/setProperties (maybe we should simply have another one "RepoWithProps") I believe the same workflow engine could be connected to any repository implementation attached to that interface.
The drawback to that approach is that other access paths to the repo are not attached to the workflow (of course you can do things like routing your WebDAV traffic through Cocoon).
On a side note, I believe in addition to components implementing the Repository interface we could/should come up with a set of components (like a WorkflowManager :-) sitting on top of that repository. But this gets too much offtopic.
The workflow our customer has goes roughly like this:
------------ ------------- --------
|tobereviewed|------>|beingreviewed|------>|released|
------------ ------------- --------
/|\ | |
| | |
| \|/ \|/
-------------- ------------- ------
|beingprocessed|<--->|tobeprocessed|<------|online|
-------------- ------------- ------
/|\ | |
| \|/ |
| -------- |
--------------->|archived|<-------------
--------The boxes represent states a particular document might be in and the arrows are transitions allowed. Authorization is also taken into account in a sense that there are 2 globally valid roles (like user and editor :-) and each user must possess one of those. Some transistions are only allowed by one of those roles (all this looks very similar to your use cases - what surprise again :-). "tobeprocessed" might have a username attached to it and "beingprocessed" always has a username attached to it (the name of the user who put the document into the "beingprocessed" state) and only this user is allowed to edit this document and to transfer it into another state. There is another level of authorization (such as who might create/delete and edit docs at particular repo locations) implemented via WebDAV ACL.
We always capture the states as being properties of a document (that means there is no such thing as a workflow instance). So a pending task list for a user might simply be implemented by a DASL (or whatever query language the particular repository implementation might implement) query that goes like:
-give me all documents in "tobeprocessed" state
-give me all documents in "tobeprocessed" state with my name attached
-give me all documents in "tobereviewed" state
and doesn't have to be a concern of the workflow engine at all.
So what might such a WorkflowManager look like? Our WorkflowManager (and I hereby propose to follow that path :-) is implemented as a Avalon component with the following interface:
-setState(docURI, requestedState, user, optionalObject)
-getState(docURI)
-getAllowedActions(docURI, user)
-setRepo(repo)
I hope the general meaning of the parameters is clear (and the details may be discussed later). "docURI" might be just an object identifier or an object carrying things like doctype information (so that your second precondition is met). "requestedState" might be a State object, an Action object, an Event object, simply a string or whatever. "optionalObject" in our case is string carrying a comment.
Such an interface might be high level enough to allow for plugging in slightly different approaches.
WDYT?
Oh, one more thing that might be worth discussing first. I reasonate with many of the things Stefano said, except the thing about connecting workflow to flow (or to continuations). Maybe I'm just not getting the picture (and I thought a lot about it) but I couldn't think of how continuations make my life easier. Maybe that is because I don't think about workflow as being instances of something (but this seemed to go along with Stefano's thoughts). Now I'm not sure about that anymore ...
Guido
--
Guido Casper
-------------------------------------------------
S&N AG, Competence Center Open Source
Tel.: +49-5251-1581-87
Klingenderstr. 5 mailto:[EMAIL PROTECTED]
D-33100 Paderborn http://www.s-und-n.de
-------------------------------------------------Johan Stuyts wrote:
Experience with workflow at Hippo Webworks ==========================================
At Hippo we used OSWorkflow to implement a workflow solution in a demo. Below are our experiences.
As people with different levels of experience are interested in workflow I will start with a (very) brief introduction to workflow.
Workflow introduction --------------------- Very simply put workflow serves two purposes: - to determine who can do what at which time with an object; - to generate a list of pending tasks for users.
An example of the first is that an editor (who) can only publish (do what) a document (an object) after a writer has asked for a review (at which time).
The lists of documents to be reviewed is an example of a pending task list for an editor.
Each object type can have its own specific workflow.
The demo workflow
-----------------
The demo we created has a workflow for a basic document type, a web page. I have attached a diagram of it.
A document gets created by a writer. The writer is not allowed to publish his document directly, he has to ask the editor for review.
The editor can easily review documents because we generate a list of documents waiting for review. The editor can click on the document and can either approve or disapprove. If the document gets approved it is published on the public server.
If the document gets disapproved the writer can not ask for a review without editing it first. Editing the document when it has been approved will bring the document back to the editing state too. After making his changes the user can ask for a review of the new version.
Implementation
--------------
For the document repository we use Slide. For the workflow engine we used OSWorkflow. We connected these two using Slide interceptors.
When a document is created the interceptor checks to see whether a workflow already exists. It does this by retrieving the workflow ID from a WebDAV property of the document. If it doesn't exist a new workflow is created in the workflow store.
When our frontend retrieves the tree of documents, the interceptor will retrieve the workflow for each document. Looking at the role of the user the interceptor will determine which actions are enabled. The enabled actions (including their display text and activation URLs) are set in a WebDAV property of the document.
For the generation of the pending task list we used the OSWorkflow query API to generate the documents which are in the waiting-for-review state. The approve and disapprove actions are passed to the frontend in the same way as the commands for a writer.
Not all actions are directly shown in the menu, because the user invokes them implicitly. The edit action for example is invoked by the interceptor each time the user saves the document.
Issues
------
We encountered issues with both slides and OSWorkflow during the implementation.
Before we used Slide, we used the Cocoon repository. The semantics of the repository interceptors and the Slide interceptors is not the same. With the repository interceptor we were able to add a property to the document in postStoreContent(...). In Slide we had to do this in preStoreContent(...).
Apart from that the Slide interceptors work very well, but (in the version of Slide we used) they get called a lot. A single store of a document invoked preStoreContent(...) and postStoreContent(...) multiple times.
OSWorkflow performed great too. The only disadvantage was the complexity of state machines that can be expressed. As you can see in the attached diagram nested states are used. OSWorkflow does not support these.
Although the attached workflow does not contain parallel states, we think it might be needed for some document types. A newsletter for example follows the same workflow as the attached one. But parallel to this is a mailing workflow for sending it to the newsletter subscribers.
In the mailing workflow the user can send a test email of the current version to himself. When he is satisfied he can send the final version to the newsletter subscribers. After this, he can neither send a test email nor send it to the subscribers.
But what to do if a mistake in the newsletter is found after sending it to the subscribers? The subscribers won't be happy to receive another copy, so the mailing actions should stay blocked. But not correcting the newsletter on the website looks sloppy. Therefore the editing/reviewing/publishing workflow has to remain active.
Workflow requirements
---------------------
Building an effective and solid workflow solution requires two preconditions. Both are outside the scope of the workflow framework:
- understandable role assignment (from a user's perspective) and simple role retrieval;
- typed document repository. This is necessary to enable different document types having different workflows attached to them.
When these two preconditions are met, the workflow framework must meet the following basic requirements:
- the ability to specify under what conditions an action can be invoked. Authorization is considered a specific type of condition;
- the ability to retrieve the actions which can be invoked by a particalur user at this moment;
- the ability to query the workflow store for objects which are in a specific state and are relevant to the current user.
The requirements on the main function of a workflow framework, state-machine evaluation, depend on the complexity of the use cases which need to be implemented.
Although we implemented the workflow in our demo using OSWorkflow we were not completely satisfied. Some actions, edit and delete for example, should be available in more than one state. We had to promote these actions to global actions, and add conditions to these actions to check whether the workflow is in a valid state. Because of this creative coding the logic of the workflow moved out of its context and difficult to read from the workflow configuration.
In our opinion a workflow framework supporting almost all constucts from UML state machines is needed to be able to build powerful, and still easy-to-understand solutions.
Where to go next
----------------
Our next goals are to make sure the two preconditions are met. Concurrently we will be creating workflow use-cases to determine how complex state machines need to be to implement these use cases.
We are very interested in hearing about use cases and workflow-framework experiences from other people. We will update the existing page about workflow on the Cocoon Wiki (http://wiki.cocoondev.org/Wiki.jsp?page=Workflow) with our experiences.
Johan Stuyts Hippo Webworks http://www.hippo.nl/ johan (at) hippo (dot) nl
------------------------------------------------------------------------
