forked from seam2/jboss-seam
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Jbpm.xml
executable file
·865 lines (702 loc) · 33.2 KB
/
Jbpm.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
<chapter id="jbpm">
<title>Pageflows and business processes</title>
<para>
JBoss jBPM is a business process management engine for any Java SE or EE
environment. jBPM lets you represent a business process or user
interaction as a graph of nodes representing wait states, decisions,
tasks, web pages, etc. The graph is defined using a simple, very readable,
XML dialect called jPDL, and may be edited and visualised graphically using
an eclipse plugin. jPDL is an extensible language, and is suitable for
a range of problems, from defining web application page flow, to traditional
workflow management, all the way up to orchestration of services in a SOA
environment.
</para>
<para>
Seam applications use jBPM for two different problems:
</para>
<itemizedlist>
<listitem>
<para>
Defining the pageflow involved in complex user interactions. A jPDL
process definition defines the page flow for a single conversation.
A Seam conversation is considered to be a relatively short-running
interaction with a single user.
</para>
</listitem>
<listitem>
<para>
Defining the overarching business process. The business process may span
multiple conversations with multiple users. Its state is persistent in
the jBPM database, so it is considered long-running. Coordination of
the activities of multiple users is a much more complex problem than
scripting an interaction with a single user, so jBPM offers sophisticated
facilities for task management and dealing with multiple concurrent paths
of execution.
</para>
</listitem>
</itemizedlist>
<para>
Don't get these two things confused! They operate at very different levels
or granularity. <emphasis>Pageflow</emphasis>, <emphasis>conversation</emphasis>
and <emphasis>task</emphasis> all refer to a single
interaction with a single user. A business process spans many tasks.
Futhermore, the two applications of jBPM are totally orthogonal. You can
use them together or independently or not at all.
</para>
<para>
You don't have to know jPDL to use Seam. If you're perfectly happy defining
pageflow using JSF or Seam navigation rules, and if your application is more
data-driven that process-driven, you probably don't need jBPM. But we're
finding that thinking of user interaction in terms of a well-defined graphical
representation is helping us build more robust applications.
</para>
<section>
<title>Pageflow in Seam</title>
<para>
There are two ways to define pageflow in Seam:
</para>
<itemizedlist>
<listitem>
<para>
Using JSF or Seam navigation rules - the <emphasis>stateless navigation
model</emphasis>
</para>
</listitem>
<listitem>
<para>
Using jPDL - the <emphasis>stateful navigation model</emphasis>
</para>
</listitem>
</itemizedlist>
<para>
Very simple applications will only need the stateless navigation
model. Very complex applications will use both models in different
places. Each model has its strengths and weaknesses!
</para>
<section>
<title>The two navigation models</title>
<para>
The stateless model defines a mapping from a set of named, logical
outcomes of an event directly to the resulting page of the view.
The navigation rules are entirely oblivious to any state held by
the application other than what page was the source of the event.
This means that your action listener methods must sometimes make
decisions about the page flow, since only they have access to the
current state of the application.
</para>
<para>
Here is an example page flow definition using JSF navigation
rules:
</para>
<programlisting role="XML"><![CDATA[<navigation-rule>
<from-view-id>/numberGuess.xhtml</from-view-id>
<navigation-case>
<from-outcome>guess</from-outcome>
<to-view-id>/numberGuess.xhtml</to-view-id>
<redirect/>
</navigation-case>
<navigation-case>
<from-outcome>win</from-outcome>
<to-view-id>/win.xhtml</to-view-id>
<redirect/>
</navigation-case>
<navigation-case>
<from-outcome>lose</from-outcome>
<to-view-id>/lose.xhtml</to-view-id>
<redirect/>
</navigation-case>
</navigation-rule>]]></programlisting>
<para>
Here is the same example page flow definition using Seam navigation
rules:
</para>
<programlisting role="XML"><![CDATA[<page view-id="/numberGuess.xhtml">
<navigation>
<rule if-outcome="guess">
<redirect view-id="/numberGuess.xhtml"/>
</rule>
<rule if-outcome="win">
<redirect view-id="/win.xhtml"/>
</rule>
<rule if-outcome="lose">
<redirect view-id="/lose.xhtml"/>
</rule>
</navigation>
</page>]]></programlisting>
<para>
If you find navigation rules overly verbose, you can return view ids
directly from your action listener methods:
</para>
<programlisting role="JAVA"><![CDATA[public String guess() {
if (guess==randomNumber) return "/win.xhtml";
if (++guessCount==maxGuesses) return "/lose.xhtml";
return null;
}]]></programlisting>
<para>
Note that this results in a redirect. You can even specify parameters
to be used in the redirect:
</para>
<programlisting role="JAVA"><![CDATA[public String search() {
return "/searchResults.xhtml?searchPattern=#{searchAction.searchPattern}";
}]]></programlisting>
<para>
The stateful model defines a set of transitions between a set of
named, logical application states. In this model, it is possible
to express the flow of any user interaction entirely in the jPDL
pageflow definition, and write action listener methods that are
completely unaware of the flow of the interaction.
</para>
<para>
Here is an example page flow definition using jPDL:
</para>
<programlisting role="XML"><![CDATA[<pageflow-definition name="numberGuess">
<start-page name="displayGuess" view-id="/numberGuess.xhtml">
<redirect/>
<transition name="guess" to="evaluateGuess">
<action expression="#{numberGuess.guess}" />
</transition>
</start-page>
<decision name="evaluateGuess" expression="#{numberGuess.correctGuess}">
<transition name="true" to="win"/>
<transition name="false" to="evaluateRemainingGuesses"/>
</decision>
<decision name="evaluateRemainingGuesses" expression="#{numberGuess.lastGuess}">
<transition name="true" to="lose"/>
<transition name="false" to="displayGuess"/>
</decision>
<page name="win" view-id="/win.xhtml">
<redirect/>
<end-conversation />
</page>
<page name="lose" view-id="/lose.xhtml">
<redirect/>
<end-conversation />
</page>
</pageflow-definition>]]></programlisting>
<mediaobject>
<imageobject role="fo">
<imagedata fileref="images/plugin-jbpm-numguess.png" align="center" scalefit="1"/>
</imageobject>
<imageobject role="html">
<imagedata fileref="images/plugin-jbpm-numguess.png" align="center"/>
</imageobject>
</mediaobject>
<para>
There are two things we notice immediately here:
</para>
<itemizedlist>
<listitem>
<para>
The JSF/Seam navigation rules are <emphasis>much</emphasis> simpler.
(However, this obscures the fact that the underlying Java code
is more complex.)
</para>
</listitem>
<listitem>
<para>
The jPDL makes the user interaction immediately understandable,
without us needing to even look at the facelets template or Java code.
</para>
</listitem>
</itemizedlist>
<para>
In addition, the stateful model is more <emphasis>constrained</emphasis>.
For each logical state (each step in the page flow), there are a
constrained set of possible transitions to other states. The stateless
model is an <emphasis>ad hoc</emphasis> model which is suitable to
relatively unconstrained, freeform navigation where the user decides
where he/she wants to go next, not the application.
</para>
<para>
The stateful/stateless navigation distinction is quite similar to
the traditional view of modal/modeless interaction. Now, Seam
applications are not usually modal in the simple sense of the
word - indeed, avoiding application modal behavior is one of the
main reasons for having conversations! However, Seam applications
can be, and often are, modal at the level of a particular
conversation. It is well-known that modal behavior is something
to avoid as much as possible; it is very difficult to predict the
order in which your users are going to want to do things! However,
there is no doubt that the stateful model has its place.
</para>
<para>
The biggest contrast between the two models is the back-button
behavior.
</para>
</section>
<section>
<title>Seam and the back button</title>
<para>
When JSF or Seam navigation rules are used, Seam lets the user freely
navigate via the back, forward and refresh buttons. It is the
responsibility of the application to ensure that conversational
state remains internally consistent when this occurs. Experience
with the combination of web application frameworks like Struts
or WebWork - that do not support a conversational model - and
stateless component models like EJB stateless session beans
or the Spring framework has taught many developers that this is
close to impossible to do! However, our experience is that in
the context of Seam, where there is a well-defined conversational
model, backed by stateful session beans, it is actually quite
straightforward. Usually it is as simple as combining the use
of <literal>no-conversation-view-id</literal> with null
checks at the beginning of action listener methods. We consider
support for freeform navigation to be almost always desirable.
</para>
<para>
In this case, the <literal>no-conversation-view-id</literal>
declaration goes in <literal>pages.xml</literal>. It tells
Seam to redirect to a different page if a request originates
from a page rendered during a conversation, and that conversation
no longer exists:
</para>
<programlisting role="XML"><![CDATA[<page view-id="/checkout.xhtml"
no-conversation-view-id="/main.xhtml"/>]]></programlisting>
<para>
On the other hand, in the stateful model, using the back button is
interpreted as an undefined transition back to a previous state.
Since the stateful model enforces a defined set of transitions
from the current state, the back button is not permitted by default
in the stateful model! Seam transparently detects the use of the
back button, and blocks any attempt to perform an action from
a previous, "stale" page, and simply redirects the user to
the "current" page (and displays a faces message). Whether you
consider this a feature or a limitation of the stateful model
depends upon your point of view: as an application developer,
it is a feature; as a user, it might be frustrating! You can
enable backbutton navigation from a particular page node by
setting <literal>back="enabled"</literal>.
</para>
<programlisting role="XML"><![CDATA[<page name="checkout"
view-id="/checkout.xhtml"
back="enabled">
<redirect/>
<transition to="checkout"/>
<transition name="complete" to="complete"/>
</page>]]></programlisting>
<para>
This allows navigation via the back button <emphasis>from</emphasis>
the <literal>checkout</literal> state to <emphasis>any previous
state!</emphasis>
</para>
<note>
If a page is set to redirect after a transition, it is not possible
to use the back button to return to that page even when back is
enabled on a page later in the flow. The reason is because Seam
stores information about the pageflow in the page scope and the back
button must result in a POST for that information to be restored
(i.e., a Faces request). A redirect severs this linkage.
</note>
<para>
Of course, we still need to define what happens if a request
originates from a page rendered during a pageflow, and the
conversation with the pageflow no longer exists. In this case,
the <literal>no-conversation-view-id</literal> declaration
goes into the pageflow definition:
</para>
<programlisting role="XML"><![CDATA[<page name="checkout"
view-id="/checkout.xhtml"
back="enabled"
no-conversation-view-id="/main.xhtml">
<redirect/>
<transition to="checkout"/>
<transition name="complete" to="complete"/>
</page>]]></programlisting>
<para>
In practice, both navigation models have their place, and you'll
quickly learn to recognize when to prefer one model over the other.
</para>
</section>
</section>
<section>
<title>Using jPDL pageflows</title>
<section>
<title>Installing pageflows</title>
<para>
We need to install the Seam jBPM-related components, and place the
pageflow definitions (using the standard <literal>.jpdl.xml</literal>
extension) inside a Seam archive (an archive which
contains a <literal>seam.properties</literal> file):
</para>
<programlisting role="XML"><![CDATA[<bpm:jbpm />]]></programlisting>
<para>
We can also explicitly tell Seam where to find our pageflow
definition. We specify this in <literal>components.xml</literal>:
</para>
<programlisting role="XML"><![CDATA[<bpm:jbpm>
<bpm:pageflow-definitions>
<value>pageflow.jpdl.xml</value>
</bpm:pageflow-definitions>
</bpm:jbpm>]]></programlisting>
</section>
<section>
<title>Starting pageflows</title>
<para>
We "start" a jPDL-based pageflow by specifying the name of the
process definition using a <literal>@Begin</literal>,
<literal>@BeginTask</literal> or <literal>@StartTask</literal>
annotation:
</para>
<programlisting role="JAVA"><![CDATA[@Begin(pageflow="numberguess")
public void begin() { ... }]]></programlisting>
<para>Alternatively we can start a pageflow using pages.xml:</para>
<programlisting role="XML"><![CDATA[<page>
<begin-conversation pageflow="numberguess"/>
</page>]]></programlisting>
<para>
If we are beginning the pageflow during the <literal>RENDER_RESPONSE</literal>
phase — during a <literal>@Factory</literal> or <literal>@Create</literal>
method, for example — we consider ourselves to be already at the page being
rendered, and use a <literal><start-page></literal> node as the first node
in the pageflow, as in the example above.
</para>
<para>
But if the pageflow is begun as the result of an action listener invocation,
the outcome of the action listener determines which is the first page to be
rendered. In this case, we use a <literal><start-state></literal> as
the first node in the pageflow, and declare a transition for each possible
outcome:
</para>
<programlisting role="XML"><![CDATA[<pageflow-definition name="viewEditDocument">
<start-state name="start">
<transition name="documentFound" to="displayDocument"/>
<transition name="documentNotFound" to="notFound"/>
</start-state>
<page name="displayDocument" view-id="/document.jsp">
<transition name="edit" to="editDocument"/>
<transition name="done" to="main"/>
</page>
...
<page name="notFound" view-id="/404.jsp">
<end-conversation/>
</page>
</pageflow-definition>]]></programlisting>
</section>
<section>
<title>Page nodes and transitions</title>
<para>
Each <literal><page></literal> node represents a state where
the system is waiting for user input:
</para>
<programlisting role="XML"><![CDATA[<page name="displayGuess" view-id="/numberGuess.jsp">
<redirect/>
<transition name="guess" to="evaluateGuess">
<action expression="#{numberGuess.guess}" />
</transition>
</page>]]></programlisting>
<para>
The <literal>view-id</literal> is the JSF view id. The <literal><redirect/></literal>
element has the same effect as <literal><redirect/></literal> in a
JSF navigation rule: namely, a post-then-redirect behavior, to overcome problems
with the browser's refresh button. (Note that Seam propagates conversation contexts
over these browser redirects. So there is no need for a Ruby on Rails style "flash"
construct in Seam!)
</para>
<para>
The transition name is the name of a JSF outcome triggered by clicking
a command button or command link in <literal>numberGuess.jsp</literal>.
</para>
<programlisting role="XHTML"><![CDATA[<h:commandButton type="submit" value="Guess" action="guess"/>]]></programlisting>
<para>
When the transition is triggered by clicking this button, jBPM will activate the
transition action by calling the <literal>guess()</literal> method of the
<literal>numberGuess</literal> component. Notice that the syntax used for
specifying actions in the jPDL is just a familiar JSF EL expression, and that
the transition action handler is just a method of a Seam component in the
current Seam contexts. So we have exactly the same event model for jBPM events
that we already have for JSF events! (The <emphasis>One Kind of Stuff</emphasis>
principle.)
</para>
<para>
In the case of a null outcome (for example, a command button with no
<literal>action</literal> defined), Seam will signal the transition with no
name if one exists, or else simply redisplay the page if all transitions
have names. So we could slightly simplify our example pageflow and this button:
</para>
<programlisting role="XHTML"><![CDATA[<h:commandButton type="submit" value="Guess"/>]]></programlisting>
<para>
Would fire the following un-named transition:
</para>
<programlisting role="XML"><![CDATA[<page name="displayGuess" view-id="/numberGuess.jsp">
<redirect/>
<transition to="evaluateGuess">
<action expression="#{numberGuess.guess}" />
</transition>
</page>]]></programlisting>
<para>
It is even possible to have the button call an action method, in which case the
action outcome will determine the transition to be taken:
</para>
<programlisting role="XHTML"><![CDATA[<h:commandButton type="submit" value="Guess" action="#{numberGuess.guess}"/>]]></programlisting>
<programlisting role="XML"><![CDATA[<page name="displayGuess" view-id="/numberGuess.jsp">
<transition name="correctGuess" to="win"/>
<transition name="incorrectGuess" to="evaluateGuess"/>
</page>]]></programlisting>
<para>
However, this is considered an inferior style, since it moves responsibility for
controlling the flow out of the pageflow definition and back into the other
components. It is much better to centralize this concern in the pageflow itself.
</para>
</section>
<section>
<title>Controlling the flow</title>
<para>
Usually, we don't need the more powerful features of jPDL when defining pageflows.
We do need the <literal><decision></literal> node, however:
</para>
<programlisting role="XML"><![CDATA[<decision name="evaluateGuess" expression="#{numberGuess.correctGuess}">
<transition name="true" to="win"/>
<transition name="false" to="evaluateRemainingGuesses"/>
</decision>]]></programlisting>
<para>
A decision is made by evaluating a JSF EL expression in the Seam contexts.
</para>
</section>
<section>
<title>Ending the flow</title>
<para>
We end the conversation using <literal><end-conversation></literal>
or <literal>@End</literal>. (In fact, for readability, use of
<emphasis>both</emphasis> is encouraged.)
</para>
<programlisting role="XML"><![CDATA[<page name="win" view-id="/win.jsp">
<redirect/>
<end-conversation/>
</page>]]></programlisting>
<para>
Optionally, we can end a task, specify a jBPM <literal>transition</literal>
name. In this case, Seam will signal the end of the current task in the
overarching business process.
</para>
<programlisting role="XML"><![CDATA[<page name="win" view-id="/win.jsp">
<redirect/>
<end-task transition="success"/>
</page>]]></programlisting>
</section>
<section>
<title>Pageflow composition</title>
<para>
It is possible to compose pageflows and have one pageflow pause
pause while another pageflow executes. The <literal><process-state></literal>
node pauses the outer pageflow, and begins execution of a named
pageflow:
</para>
<programlisting role="XML"><![CDATA[<process-state name="cheat">
<sub-process name="cheat"/>
<transition to="displayGuess"/>
</process-state>]]></programlisting>
<para>
The inner flow begins executing at a <literal><start-state></literal>
node. When it reaches an <literal><end-state></literal> node,
execution of the inner flow ends, and execution of the outer flow
resumes with the transition defined by the <literal><process-state></literal>
element.
</para>
</section>
</section>
<section>
<title>Business process management in Seam</title>
<para>
A business process is a well-defined set of tasks that must
be performed by users or software systems according to
well-defined rules about <emphasis>who</emphasis> can perform
a task, and <emphasis>when</emphasis> it should be performed.
Seam's jBPM integration makes it easy to display lists of
tasks to users and let them manage their tasks. Seam also
lets the application store state associated with the business
process in the <literal>BUSINESS_PROCESS</literal> context,
and have that state made persistent via jBPM variables.
</para>
<para>
A simple business process definition looks much the same as a
page flow definition (<emphasis>One Kind of Stuff</emphasis>),
except that instead of <literal><page></literal> nodes,
we have <literal><task-node></literal> nodes. In a
long-running business process, the wait states are where the
system is waiting for some user to log in and perform a task.
</para>
<programlisting role="XML"><![CDATA[<process-definition name="todo">
<start-state name="start">
<transition to="todo"/>
</start-state>
<task-node name="todo">
<task name="todo" description="#{todoList.description}">
<assignment actor-id="#{actor.id}"/>
</task>
<transition to="done"/>
</task-node>
<end-state name="done"/>
</process-definition>]]></programlisting>
<mediaobject>
<imageobject role="fo">
<imagedata fileref="images/plugin-jbpm-todo.png" align="center" scalefit="1"/>
</imageobject>
<imageobject role="html">
<imagedata fileref="images/plugin-jbpm-todo.png" align="center"/>
</imageobject>
</mediaobject>
<para>
It is perfectly possible that we might have both jPDL business
process definitions and jPDL pageflow definitions in the
same project. If so, the relationship between the two is that
a single <literal><task></literal> in a business process
corresponds to a whole pageflow
<literal><pageflow-definition></literal>
</para>
</section>
<section>
<title>Using jPDL business process definitions</title>
<section>
<title>Installing process definitions</title>
<para>
We need to install jBPM, and tell it where to find the
business process definitions:
</para>
<programlisting role="XML"><![CDATA[<bpm:jbpm>
<bpm:process-definitions>
<value>todo.jpdl.xml</value>
</bpm:process-definitions>
</bpm:jbpm>]]></programlisting>
<para>
As jBPM processes are persistent across application restarts,
when using Seam in a production environment you won't want to
install the process definition every time the application starts.
Therefore, in a production environment, you'll need to deploy
the process to jBPM outside of Seam. In other words, only install
process definitions from <literal>components.xml</literal> when
developing your application.
</para>
</section>
<section>
<title>Initializing actor ids</title>
<para>
We always need to know what user is currently logged in.
jBPM "knows" users by their <emphasis>actor id</emphasis>
and <emphasis>group actor ids</emphasis>. We specify the
current actor ids using the built in Seam component named
<literal>actor</literal>:
</para>
<programlisting role="JAVA"><![CDATA[@In Actor actor;
public String login() {
...
actor.setId( user.getUserName() );
actor.getGroupActorIds().addAll( user.getGroupNames() );
...
}]]></programlisting>
</section>
<section>
<title>Initiating a business process</title>
<para>
To initiate a business process instance, we use the
<literal>@CreateProcess</literal> annotation:
</para>
<programlisting role="JAVA"><![CDATA[@CreateProcess(definition="todo")
public void createTodo() { ... }]]></programlisting>
<para>Alternatively we can initiate a business process using pages.xml:</para>
<programlisting role="XML"><![CDATA[<page>
<create-process definition="todo" />
</page>]]></programlisting>
</section>
<section>
<title>Task assignment</title>
<para>
When a process reaches a task node, task instances are created. These must be
assigned to users or user groups. We can either hardcode our actor ids, or
delegate to a Seam component:
</para>
<programlisting role="XML"><![CDATA[<task name="todo" description="#{todoList.description}">
<assignment actor-id="#{actor.id}"/>
</task>]]></programlisting>
<para>
In this case, we have simply assigned the task to the current user.
We can also assign tasks to a pool:
</para>
<programlisting role="XML"><![CDATA[<task name="todo" description="#{todoList.description}">
<assignment pooled-actors="employees"/>
</task>]]></programlisting>
</section>
<section>
<title>Task lists</title>
<para>
Several built-in Seam components make it easy to display task lists.
The <literal>pooledTaskInstanceList</literal> is a list of pooled tasks
that users may assign to themselves:
</para>
<programlisting role="XHTML"><![CDATA[<h:dataTable value="#{pooledTaskInstanceList}" var="task">
<h:column>
<f:facet name="header">Description</f:facet>
<h:outputText value="#{task.description}"/>
</h:column>
<h:column>
<s:link action="#{pooledTask.assignToCurrentActor}" value="Assign" taskInstance="#{task}"/>
</h:column>
</h:dataTable>]]></programlisting>
<para>
Note that instead of <literal><s:link></literal> we could have used
a plain JSF <literal><h:commandLink></literal>:
</para>
<programlisting role="XHTML"><![CDATA[<h:commandLink action="#{pooledTask.assignToCurrentActor}">
<f:param name="taskId" value="#{task.id}"/>
</h:commandLink>]]></programlisting>
<para>
The <literal>pooledTask</literal> component is a built-in component that
simply assigns the task to the current user.
</para>
<para>
The <literal>taskInstanceListForType</literal> component includes tasks of
a particular type that are assigned to the current user:
</para>
<programlisting role="XHTML"><![CDATA[<h:dataTable value="#{taskInstanceListForType['todo']}" var="task">
<h:column>
<f:facet name="header">Description</f:facet>
<h:outputText value="#{task.description}"/>
</h:column>
<h:column>
<s:link action="#{todoList.start}" value="Start Work" taskInstance="#{task}"/>
</h:column>
</h:dataTable>]]></programlisting>
</section>
<section>
<title>Performing a task</title>
<para>
To begin work on a task, we use either <literal>@StartTask</literal>
or <literal>@BeginTask</literal> on the listener method:
</para>
<programlisting role="JAVA"><![CDATA[@StartTask
public String start() { ... }]]></programlisting>
<para>Alternatively we can begin work on a task using pages.xml:</para>
<programlisting role="XML"><![CDATA[<page>
<start-task />
</page>]]></programlisting>
<para>
These annotations begin a special kind of conversation that has
significance in terms of the overarching business process. Work done
by this conversation has access to state held in the business
process context.
</para>
<para>
If we end the conversation using <literal>@EndTask</literal>, Seam
will signal the completion of the task:
</para>
<programlisting role="JAVA"><![CDATA[@EndTask(transition="completed")
public String completed() { ... }]]></programlisting>
<para>Alternatively we can use pages.xml:</para>
<programlisting role="XML"><![CDATA[<page>
<end-task transition="completed" />
</page>]]></programlisting>
<para>
You can also use EL to specify the transition in pages.xml.
</para>
<para>
At this point, jBPM takes over and continues executing the business process
definition. (In more complex processes, several tasks might need to be
completed before process execution can resume.)
</para>
<para>
Please refer to the jBPM documentation for a more thorough overview of
the sophisticated features that jBPM provides for managing complex
business processes.
</para>
</section>
</section>
</chapter>