This package defines the application invocation interface used
by the workflow package to invoke tool agents that control
applications.
Java classes that are to be used as tool agents must implement
the interface {@link de.danet.an.workflow.spis.aii.ToolAgent
ToolAgent }. Tool agents are declared in a workflow
using the application tag in the XPDL. This
declaration is associated with the implementation class of
ToolAgent using an extension. The extension syntax
supported allows to specify the Java class to use and additional
properties of the tool agent (see the User Manual for
details).
Note that a tool agent can be implemented with full
functionallity based on the tool agent interface only. The
remainder of this package description explains how tool agent
implementation may be simplified and how the performance of tool
agent invocations may be improved. As with the {@link
de.danet.an.workflow.api client API}, we have tried to keep this
extended interface as independant of the implementation
framework (J2EE) as possible. However, this attempt is limited
by requirements imposed by transaction handling. While the
interfaces could be kept clean of dependencies on J2EE
interfaces or classes, their usage pattern is partially
motivated by EJB transaction semantics.
From the workflow engine's point of view, tool agent invocation
is asynchronous, i.e. it does not expect a result from the
{@link de.danet.an.workflow.spis.aii.ToolAgent#invoke
invoke } method. The invoked application must at
some point in time call {@link
de.danet.an.workflow.omgcore.WfActivity#setResult
WfActivity.setResult } and {@link
de.danet.an.workflow.omgcore.WfActivity#complete
WfActivity.complete } to signal completion of its
work. Although the tool agent model assumes that this is done
"later" (e.g. by the application process), these calls may also
be made in the implementation of the invoke method,
thus effectively combining the tool agent with the application
that it controls (making the tool agent a tool).
If you try to call setResult and
complete in the invoke method of your
tool implementation, you'll sooner or later notice that these
methods (being remote calls) may throw
RemoteException s, indicating some temporary
failure. If you do not handle these exceptions, they will be
handled by the workflow engine and your tool will simply be
re-invoked. If, however, your invoke method is "expensive" or
has side effects, you may not want it to be re-executed because
of a temporary failure during setResult or
complete .
Consequently, you put a while loop around these calls, repeating
them until they run without a
RemoteException . Regrettably, this is where EJB
semantics come in. While the repeat pattern works in a
stand-alone EJB client, it won't work here because
invoke is called in the context of an EJB method
and the RemoteException from setResult
or complete is noticed by the EJB container, and
the complete tool agent invocation transaction will be rolled
back. So you have to execute the calls to setResult
and complete in a new transaction. This is what
{@link
de.danet.an.workflow.spis.aii.ToolAgentContext#finishActivity
ToolAgentContext.finishActivity } has been defined
for. This method calls setResult and
complete in a new transaction (and repeats the
calls until no RemoteException is thrown). If you
want to use this method (or another method from the tool agent
context), your tool agent must implement {@link
de.danet.an.workflow.spis.aii.ContextRequester
ContextRequester } in order to receive the context
before invoke is called.
Having a closer look at transactions, there is a drawback to the
solution described above. If we look at open transactions, we
find that there is one transaction handling the tool invocation;
this has been suspended for a new transaction that executes the
actual tool agent invocation (this must be done in its own
transaction, else the workflow engine cannot terminate an
activity if an exception is thrown by the tool agent as, again,
the invoking transaction would be marked for rollback by the
application server). By calling finishActivity
during invoke , the transaction executing the tool
invocation will also be suspended in favour of the transaction
that finishes the activity. This situation may, under certain
circumstances lead to deadlocks.
To avoid these "excessive" nested transaction suspends, the
calls to setResult and complete should
better be done after tool invocation by the the same transaction
that has invoked the tool. Tools (i.e. tool agents that want to
return a result and complete the activity during
invoke ) should therefore implement {@link
de.danet.an.workflow.spis.aii.ResultProvider
ResultProvider }. This allows the tool to simply
leave the result evaluated during invoke in an
attribute from where it will be retrieved after
invoke by the workflow engine. The workflow engine
then calls setResult and complete on
the activity. Besides avoiding transaction problems, usage of
ResultProvider actually simplifies the tool
implementation.
@since V1.0
|