A client-side action consists of a client-side and a server-side implementation, so it's running partly on both sides. Whereas client-side actions run on behalf of the client user, server-side actions run on behalf of the workflow user. While the client part of the action is running, the server side transaction is still active. Client actions always have a timeout after which the action is aborted on the server side, the client side is not affected by this. ClientActions should not require user interaction, if possible, to save precious server resources.
Precisely, a client action consists of three parts:
A server-side action.
A client-side event listener.
A client-side command to execute.
The three parts will be executed in the following way:
Define the action from the workflow definition using the
class
attribute.The CoreMedia Workflow Server executes the server-side stub. It creates the parameter list which it includes in the event.
The event will be received by the client which calls the
handle()
method of the client-side event listener.The event listener has to return a callback ID to the server. You can evaluate the event and start some action from the event listener. For example, the event listener belonging to the Site Manager will execute the action the server noticed in the event.
Caution | |
---|---|
Using the Unified API, it is not possible to write the server-side parts of new client side actions. You still need the Workflow API for this. Note, however, that client-side actions can now be replaced by Unified API server-side actions in many cases, because the Unified API allows you to act on behalf of a particular user without having to open a separate connection. |
Interface to implement
Basically, the server-side stub of a client-side action must implement the interface
com.coremedia.workflow.WfAction.
For convenience and to hide the details how events are created and dispatched, you must
subclass
com.coremedia.workflow.common.actions.AbstractClientAction.
This class already includes implementations of all needed getter and setter methods, uses a
condition as guard and contains all the event logic.
AbstractClientAction
also implements a default timeout for a client action. The default timeout time is 30
seconds and can be configured using the attribute timeout
in the workflow
definition. In Example 5.1, “Example of the server-side stub for a client-side action” you see a sample action
which extends
AbstractClientAction.
Server Side
The server-side implementation of a client action is a stub which:
Assembles the argument list and passes it to the client via an event. The AbstractClientAction class includes the command and GUI parameters in the argument list. The command is the one used as the parameter in the call of the super() constructor.
Receives the clients result and creates a WfActionResult from it.
Custom clients, that are not event driven, have to be aware that while performing a
Task.accept
or Task.complete
operation on behalf of connected
clients there may be callbacks of the client action for the pending call. The callbacks have
to be executed before the server call can return.
1: public class DemoClientAction extends AbstractClientAction 2: { 3: public DemoClientAction() { 4: super("com.customer.example.workflow.action. DemoActionCommand"); 5: } 6: 7: protected HashMultiMap 8: processArguments(WfTaskInstance taskInstance, HashMultiMap map) 9: throws WfException { 10: map.put("documentType", "Article"); 11: return map; 12: } 13: 14: protected WfActionResult 15: processResult(WfTaskInstance taskInstance, WfClientActionResult result) 16: throws WfException { 17: // result processing... 18: return new WfActionResult(values, warnings, success); 19: } 20: }
Example 5.1. Example of the server-side stub for a client-side action
Line 1: Use the AbstractClientAction
instead
of the WfAction
interface.
Line 3 - 5: The constructor of your server stub. The constructor of the super class is called with the command as a parameter which should be executed on client side. This command is automatically included in the event send to the client.
Line 7 - 12: This processes the arguments which will be
included in the event. In line 10 the parameter docmentType
is added to the
HashMultiMap
. This map already contains WfClientActionListener.GUI
and WfClientActionListener.COMMAND
as default entries.
Line 14 - 19: This process the result that has been received from the client.
Client Side
The client-side must have a WfClientActionListener
installed (see
Example 5.2, “Example of an action listener”) which handles the incoming
action events.
The callback ID obtained by
WfClientActionEvent.getCallbackId
must be returned in the actions result so that the CoreMedia Workflow Server can associate request and callback.WfClientActionEvent.getParameters
returns the call parameters as encoded by the server side stub. For the previous example, the parameters would contain the stringsdocumentType
andArticle
.The event's other methods are reserved for internal use.
All predefined client actions use a property/value encoding for the action parameters. Everything is encoded as a
java.lang.String
.
Note, that the Site Manager has a generic client listener, that tries to find and execute an appropriate hox.corem.editor.commands.Command. Have a look at the Editor Developer Manual for details.
1: package com.customer.example.workflow.action; 2: 3: import com.coremedia.workflow.*; 4: import com.coremedia.workflow.common.actions.ClientActionResult; 5: 6: public class DemoClientActionListener implements WfClientActionListener { 7: 8: public DemoClientActionListener() { 9: } 10: 11: public WfClientActionResult handle(WfClientActionEvent actionEvent) { 12: String[] parameters = actionEvent.getParameters(); 13: System.out.println("parameters.length="+ parameters.length); 14: for (int i=0; i < parameters.length; i++) { 15: System.out.println("parameters["+i+"]="+ parameters[i]); 16: } 17: return new ClientActionResult(actionEvent. getCallbackId()); 18: } 19: }
Example 5.2. Example of an action listener
Line 6: The client listener must implement WfClientActionListener.
Line 11: This method must be implemented. It gets the event as a parameter. Here you can implement your functionality evaluating the information from the event.
Line 12 -15: This is only a simple example. The parameters of the event are read in an array and are printed out.
Line 17: An important line: The client listener must return a ClientActionResult containing at least the callback ID. It is also possible to return more information to the server. See the CoreMedia Workflow API documentation for more details on ClientActionResult.
Command for the Site Manager
In Example 5.3, “Command executable on the Site Manager” you see an example command which is executed on the client when an appropriate event is received by the event listener of the Site Manager. For this, the action defined in Example 5.1, “Example of the server-side stub for a client-side action” has to be executed.
1: package com.customer.example.workflow.action; 2: 3: import hox.corem.editor.toolkit.*; 4: 5: public class DemoActionCommand implements Command { 6: 7: public boolean execute(Context context, Target target) { 8: System.out.println("DemoActionCommand.execute() " + "context="+context+ " " + "target="+target); 9: return true; 10: } 11: 12: public boolean isExecutable(Context context, Target target) { 13: return true; 14: } 15: 16: }
Example 5.3. Command executable on the Site Manager
Line 3: You need to import this package because you are working on the Site Manager.
Line 5: The name of the class must be the one called from the server.
Line 7 - 10: This is the method in which you implement
your actual action. The example action only prints the content of context
and
target
and returns true.
Line 12 - 14: This method returns whether the command is executable with the given target and context or not.