Automated workflows in ZK: demonstration

The following is a simple demonstration of the workflow automation extensions for ZK. The mini-application below has been created with just a ZUL file and an osworflow XML file. As you can see, the simple application logics is defined in the workflow document. The zul interface simply provides interfaces for individual steps and triggers for actions. The zkWorkflow extensions make the operation very simple.

 

ZUL code

Here is the ZUL interface that generates this example:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <workflow-application
  3. xmlns:xhtml="http://www.w3.org/1999/xhtml"
  4. xmlns="http://www.zkoss.org/2005/zul"
  5. workflow="http://localhost:8080/OLmapDemo/simple.xml" id="wapp" width="100%" border="none">
  6.  
  7. <vbox width="100%">
  8.  
  9. <groupbox width="400px" height="330px">
  10.  
  11. <caption label="Workflow interface"/>
  12.  
  13. <!--
  14. interface components for the three possible steps. Only one of them
  15. will be visible at one time. This can be overridden with the keepVisible
  16. attribute. Otherwise they're simply windows.
  17. -->
  18. <workflow-step step="sayHello" width="100%" height="330px">
  19. <vbox width="100%">
  20.  
  21. <div>This component handles the "sayHello" state of the
  22. <xhtml:a href="simple.xml"> simple.xml </xhtml:a> workflow.
  23. You are seeing it because the workflow's initial action brought you there.
  24. There are two other possible states, each with its workflow-step
  25. components. The workflow-application only visualizes the GUI
  26. components assigned to the current step, unless you override this
  27. behavior with keepVisible = true.</div>
  28.  
  29. <div>In this state, you can choose to perform two actions, one that
  30. computes the current time, and another that computes a simple
  31. string.</div>
  32.  
  33. <div>The buttons below are generated by simply creating two button-trigger
  34. components and passing the respective action names to them. Alternatively,
  35. you can create triggers as complex as you like by wrapping ZUL components
  36. in a worflow-trigger component and calling advanceWorkflow as a
  37. response to user events.</div>
  38.  
  39. <separator />
  40. <!-- triggers for actions that are relevant to this step. If you don't
  41. have the triggers, you can still advance the workflow programmatically.
  42. -->
  43. <hbox>
  44. <button-trigger action="tellTime" label="Tell time" />
  45. <button-trigger action="sayName" label="Say name" />
  46. </hbox>
  47. </vbox>
  48. </workflow-step>
  49.  
  50. <workflow-step step="showTheTime" width="100%" height="330px">
  51. <vbox width="100%">
  52. <div>
  53. This component handles the "showTheTime" step. The action that leads
  54. into this step is defined to calculate the current date and set it in
  55. the action variable "time" every time it is executed. The label below
  56. is set to react to a state transition by looking for the value of the
  57. "time" variable in the action that caused it, and setting it as the
  58. label text. You should see the time when you clicked the action button
  59. that sent you here.
  60. </div>
  61. <separator />
  62. <label>
  63. <!-- the "data" field has been set in the action by the
  64. workflow. Note that other transitions will also invoke
  65. this one with a null value, so you want to make sure
  66. that it's fine to have null as a result of
  67. getActionData.
  68. -->
  69. <attribute name="onTransition">
  70. self.setValue(event.data.getVariable("time"));
  71. </attribute>
  72. </label>
  73. <button-trigger action="goBack" label="Go back" />
  74. </vbox>
  75. </workflow-step>
  76.  
  77. <workflow-step step="showMyName" width="100%" height="330px">
  78. <vbox width="100%">
  79. <div>
  80. This component handles the "showMyName" step. The action that leads
  81. into this step defines the "name" variable. The label below
  82. simply shows it. Variables can be set by actions, steps, or
  83. globally in workflows. The variable resolver looks for a name
  84. in the action, then in the current steps, then in the workflow.
  85. </div>
  86. <div>
  87. Defining variables in steps with the same name is a simple way to
  88. track changing state in workflows. The variables are evaluated
  89. by MVEL code in the same JVM that runs your application and can
  90. be of any Java type. You can also define variables explicitly
  91. in event handlers.
  92. </div>
  93. <separator />
  94. <label>
  95. <!-- name is another workflow-computed variable defined for the
  96. action that brings us here. -->
  97. <attribute name="onTransition">
  98. self.setValue(event.data.getVariable("name"));
  99. </attribute>
  100. </label>
  101. <button-trigger action="goBack" label="Go back" />
  102. </vbox>
  103. </workflow-step>
  104.  
  105. </groupbox>
  106.  
  107. <!-- will display status message when an action that has it starts, and
  108. resets it when it ends. Useful for long-running actions, e.g. those that
  109. call another workflow or perform complex calculations.
  110. -->
  111. <label width="100%" value="Status here" id="status"
  112. onStatusMessage="status.setValue(event.data)"/>
  113.  
  114. </vbox>
  115. </workflow-application>
  116.  

Workflow code

Here is the workflow, generated with the OpenSymphony graphical workflow editor.

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE workflow PUBLIC "-//OpenSymphony Group//DTD OSWorkflow 2.8//EN" "http://www.opensymphony.com/osworkflow/workflow_2_8.dtd">
  3. <workflow>
  4. <meta name="lastModified">Thu Mar 13 14:15:45 EDT 2008</meta>
  5. <meta name="created">Thu Mar 13 14:11:13 EDT 2008</meta>
  6. <meta name="generator">OSWorkflow Designer</meta>
  7. <initial-actions>
  8. <action id="0" name="Start Workflow">
  9. <results>
  10. <unconditional-result id="4" old-status="Finished" status="Queued" step="1"/>
  11. </results>
  12. </action>
  13. </initial-actions>
  14. <steps>
  15. <step id="1" name="sayHello">
  16. <actions>
  17. <action id="5" name="tellTime" view="sayHello">
  18. <meta name="status.message">Setting current time</meta>
  19. <meta name="set.time">new java.util.Date().toString()</meta>
  20. <results>
  21. <unconditional-result id="6" old-status="Finished" status="Queued" step="2"/>
  22. </results>
  23. </action>
  24. <action id="7" name="sayName" view="sayName">
  25. <meta name="status.message">Setting name to Jack</meta>
  26. <meta name="set.name"><![CDATA["my name is Jack"]]></meta>
  27. <results>
  28. <unconditional-result id="8" old-status="Finished" status="Queued" step="3" display-name="tellName">
  29. </unconditional-result>
  30. </results>
  31. </action>
  32. </actions>
  33. </step>
  34. <step id="2" name="showTheTime">
  35. <actions>
  36. <action id="11" name="goBack" view="goBack">
  37. <results>
  38. <unconditional-result id="12" old-status="Finished" status="Queued" step="1">
  39. </unconditional-result>
  40. </results>
  41. </action>
  42. </actions>
  43. </step>
  44. <step id="3" name="showMyName">
  45. <actions>
  46. <action id="9" name="goBack" view="goBack">
  47. <results>
  48. <unconditional-result id="10" old-status="Finished" status="Queued" step="1">
  49. </unconditional-result>
  50. </results>
  51. </action>
  52. </actions>
  53. </step>
  54. </steps>
  55. </workflow>
  56.