Thanks for your comments and thoughts. Embedded below are some responses
about how the current thinking (of course, always subject to
change) addresses some of them -- if they do.
You might want to take a look at some initial code that has been checked
in to the "jakarta-commons-sandbox" repository, if you haven't yet. The
easiest way to get this is to use anonymous CVS (you'll need both
jakarta-commons-sandbox and jakarta-commons to pick up dependencies), or I
can make snapshots available.
On Wed, 15 Aug 2001, John Sigler wrote:
> Craig,
>
> Your Workflow Proposal seems like a great start. Several of us have
> played around with some workflow concepts on our current project but it
> would be great to have something integrated into Struts.
>
> We have a few concepts that weren't mentioned that we think are worth
> considering:
>
> - "bookmarkable" workflow steps: This means being able to
> store all context related to a step in such a fashion that
> the user can go back to that same the same state in the
> workflow at a later time. Bookmarkability should be
> optional (some steps may not make sense to be bookmarked)
> and so it should be able to be indicated as such when
> being defined.
>
Hmm, technically every time that a Step tells its associated Context to
"suspend" (which causes the workflow engine to return control to the
calling app), that sort of acts like a bookmark -- in the sense that, the
next time this Context is executed, it picks up where it left off. In a
web application, that happens each time you display a page and wait for
the response. So, it seems we would need to provide a way for the user to
select a different in-progress activity (or start a new one), and then
come back to this Context later. Does that sound right?
> - a workflow "history": keep a state of where the user is
> and/or has been. Allow this state to be displayed as
> breadcrumbs, a history list, or with another visual or
> navigational representation. A tag to render this
> information seems useful as well.
>
Supporting a breadcrumb trail makes a lot of sense, at least in some
applications (i.e. where you can legitimately branch to any of the
previuos spots). There isn't any direct support for this in the current
code, although Steps can have an identifier (and thus be the destination
of a branch).
Managing a breadcrumb trail in some use cases is going to get interesting
... especially if the user can loop as well as nest.
> - workflows, especially scripted workflows, will often be
> customized. The workflow configuration files should support the
> ability to override a workflow definition - one possibility
> would be to use a mechanism similar to a Java classpath. The
> primary concern here is updating installations with new
> versions of out-of-the-box workflows without overwriting any
> customized versions of those workflows.
>
This is an important point, and was raised in the jakarta-commons
discussion as well. IMHO, this needs to be addressed at several levels.
* In the core APIs, the key component abstractions are Java interfaces
(Activity, Step, Context, and so on) that can accomodate multiple
implementations ... the usual object-oriented design approach, but
lets customized workflow engines create their own implementations.
* Configuration of the static structure of a workflow Activity is
separate from execution. An XML format (as illustrated in the
proposal) is one very nice way to do it, but you can build up your
own structures as well.
* The point you are really making, though, has to do with the "registry"
of scripted Activities. There should be a hierarchical registry
so that the Activity I get when I ask for the "Enter Purchase Orders"
activity can be customized for me, customized for my department, or
the standard one. Is that what you had in mind?
> - when a workflow is started, it should be associated with a
> context that is specific to that *instance* of the workflow.
> This supports the ability for a single user to execute the
> same workflow multiple times simultaneously. In a web UI, this
> is usually associated with a user opening multiple
> windows. This implies that a workflow must have some kind of
> instance id to uniquely identify its context and also makes it
> clear that some kind of garbage-collection capability is
> needed for workflows.
>
The execution "instance" that I had in mind was the Context. A particular
Context represents the current execution state (i.e. what Step is
next) plus all the associated variables (evaluation stack, plus variables
in scopes) of the particular user's execution of a particular Activity at
a particular time, while the Activity/Step object graph that I'm operating
against is a read-only description of the activity, and can be shared.
When thinking about it, I kept mentally picturing the execution unit of a
CPU, where the "next step" property is like the instruction pointrer, and
the evaluation stack is the stack frame, and the scopes are the
registers. More than one operating system process can execute the same
(read only) copy of a program, because all their state info is kept
separate.
> - the workflow configuration files/interfaces should support
> i18n especially for labels since the labels will likely
> appear in UI menus.
>
I agree with the general philosophy, but there might be a couple of
different ways to look at it:
* The Activity/Step definitions themselves are never visible to
the end user -- only the displays presented by the user interface
will be. Those definitely have to be internationalized, and can be
(in the usual way, with <bean:message> and friends). Where we
still need linkages is when you *do* want to represent "goto
destinations" in the activity as user interface items; that can still
be defined in either the Activity flow or as part of the UI. There
are some more thoughts about this under your Struts integration
questions below.
* There will be cases where the Activity itself needs to be customized
based on who and where the user is (country-specific tax calculations,
for example), that can be handled by customizing the overall flow
(as we discussed earlier) or building conditional logic into a
single flow. The ability to do the latter is definitely in my
thoughts -- in a Struts implementation, for instance, the Context
implementation will have access to session-scope beans, so it will
be able to see (or even set) the user's Locale etc., and use them
for branching decisions.
> - the ability to define pre- and post- conditions (inputs/outputs)
> for workflow steps would aid in robusting such as ensuring valid
> workflow definitions.
>
Something that's not fleshed out in the sample code yet, but is very much
on my priority list, is pre-built Steps that can perform arbitrary
expression evaluation, conditional processing, goto, and so on. These can
be used directly in a script, or you can also provide application-specific
Step implementations (using the namespace extensibility idea if you're
using the XML data formats) that do things in a nice compact way -- much
like Struts deals with calling validate() for you on ActionForm beans.
> A few basic questions that we have:
>
> - Can you give some more detail on your initial thoughts for the
> Struts implementation? The types of questions I have are:
>
> o Where do Actions fit in with workflows/activities in
> general? Are they used entirely behind the scenes when you
> write the XML for an activity? From the proposal
> description, it sounds as if writing an Activity will not
> require Struts coding... do this imply it will generate the
> necessary Actions, etc?
>
> o Would things like Actions, ActionForms, and JSP pages need
> to be written so they are "workflow aware"?
>
> o Are you thinking you'd extend ActionMappings to have another
> layer where they can handle Activities or something else?
> Here we're wondering if there's a way to retain the overall
> model programming in Struts but allowing non-programmers to
> create workflows.
>
There are (at least) two major approaches to the Struts level integration,
and I haven't really decided which one I like better. It would be
interesting to hear people's ideas. I've given them arbitrary labels
below just to give folks something to refer back to in discussion.
(1) STANDARD ACTIONS APPROACH
* Struts would provide a single "standard action" class that interacts
with the workflow engine.
* Each "workflow" supported by a Struts application would be mapped
to a single action path, which (re)uses the same standard Action
mentioned above. So, starting a new Activity would mean just linking
to a new Action URL - the fact that there was no Context in your
session for this means you're starting a new one.
* The current execution state (i.e. Context) would be maintained in
the user's session, so that multiple people can execute the same
Activity at the same time.
* The JSP pages would be labelled with <forward> declarations as we do
now -- the particular pages for a particular activity would have
local <forward> declarations inside the <action> declaration for
that activity.
* Included in the suite of built-in Step implementations would be the
ability to call arbitrary methods of arbitrary bean instances, and
pass arbitrary arguments. Therefore, you would normally be able to
dispense with writing an Action class itself, and either script the
logic directly in the activity (certainly feasible for something
simple like logon checking) or delegate to a business logic class
or EJB just like an Action does now.
* JSP pages would be mostly independent of the fact that they are being
operated inside an Activity. However, a linkage is required in order
to provide navigation controls for branch points. Therefore, the
Struts integration layer will provide a custom tag library that
includes tags like "branch to step XYZ" when a button is pushed, or
a link is followed. Even though all of the "real" HTTP transactions
would flow back through the action URI for the activity you are
executing, the associated parameters would tell the workflow engine
what to do next.
(2) APPLICATION ACTIONS APPROACH
* Workflows would be "assembled" out of existing actions and pages.
* Individual actions would need to consult the workflow engine to
determine where to go next, rather than deciding for themselves.
* A Context object in the user's session would be used to maintain
current execution state of an activity, but there would definitely
need to be a way to support more than one.
* Pages would need to have mechanisms to create navigation links
(the same custom tag library mentioned above).
* Would rely on computational and navigation logic being performed
in Actions (as Struts-based apps do it today) more than in the
Scripts.
TRADEOFFS
* Buying in to the Standard Action approach means that it *must* be
possible to perform anything you might do in an Action, either
directly in the activity's script or by delegating to business
methods through the "arbitrary invoke" feature. I believe that
is feasible, but it bears more thought.
* Standard Actions approach tries to abstract the control flow of
an Activity away from application components, letting them focus
on "pure" business logic. Application Actions lets the app
developer participate in this, in app-specific ways.
* When retrofitting an existing Struts app, both approaches would
require modifications to the JSP pages (to present navigation
choices in a manner that the workflow engine can recognize).
For Actions, you'd be totally replacing them (in the Standard
Actions approach, or modifying them to delegate their control flow
decisions (in the Application Actions approach). Which one is
simpler depends on how careful you were in making your Actions
do *only* control flow, and delegating the real work to business
objects -- which can be happily reused under either approach.
* In the Standard Actions approach, the workflow engine directly
participates in every request processed for that activity (in a
sense, it becomes a mini-MVC-controller). Therefore, it is less
likely to "lose control" of the user interaction due to application
developers errors or misunderstandings. The Application Actions
approach will rely on Actions to be good workflow citizens and
*always* delegate control flow decisions back.
OPEN ISSUES
* How does a user initiate a particular Activity (from the point
of view of the workflow system).
* Nesting of activities (if you're an old-time BASIC hacker,
think GOSUB and RETURN :-).
* Single user can open multiple windows and execute several
activities (i.e. with separate Contexts) at the same time.
* How to prevent a malicious client from using the navigation
control inputs to attempt to bypass Steps. Maybe use the
transaction token scheme universally and transparently.
* Security issues in general (who can execute a particular flow?
can he/she do all the steps or just some?) need to be fleshed
out, and built-in Step implementations provided to support
such decisions.
* None of the discussion above has dealt with the "Process" abstraction
where the ideas include longer execution timeframes, asynchronous
events, and collaboration between users. Right now, I'm thinking
that Processes will be composed on top of Activities, but there
might be some Process-based requirements to keep in mind as we
design the Activity layer.
As you can probably gather from my descriptions, I'm currently leaning
towards the Standard Actions approach to this. As appealing as it would
be to use existing (or newly created) Action implementations, I'm
concerned that the end result will be fragile -- primarily because Action
developers are used to managing their own control flow, and there are
probably many scenarios where these control flow decisions are too complex
to be encoded in a simple workflow script.
That being said, of course, under absolutely *no* circumstances would I
contemplate de-supporting the current Action machinery. Way too many
people are building apps based on Struts 1.0 -- and they are all over the
world, so I wouldn't have any place to go hide even if I tried :-).
More seriously, workflow isn't going to solve all application design
problems. I suspect there will still be a need to create new apps that
still need the complete control that actions give you over things. But I
also believe there is a sweet spot for activities with relatively simple
flow (filling out a wizard form, for example) that are tedious to write
using just Actions, and we can make Struts-based development of such
applications much simpler by abstracting away the navigation machinery.
> - Do you think browser issues can be handled properly? Caching
> has caused us problems in the areas of handling back, forward,
> refresh buttons... for example, the previous page displays
> correctly but the actual state of the workflow has not been
> updated due to the page being cached and the context state is
> incorrect.
>
The current Struts approach to this (setting or not setting the cache
control headers) is pretty crude, but having a workflow gives us the
opportunity to be more fine-grained about those decisions. Coupled with
aggressive use of transaction tokens, I *think* we can handle most of
these concerns, but we'll always need to keep this in mind.
> thanks,
> john sigler
>
Craig