This repository has been archived by the owner on Nov 10, 2017. It is now read-only.
forked from VaclavDedik/jboss-seam
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Concepts.xml
executable file
·1312 lines (1136 loc) · 59.6 KB
/
Concepts.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
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN" "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd">
<chapter id="concepts">
<title>The contextual component model</title>
<para>
The two core concepts in Seam are the notion of a <emphasis>context</emphasis> and the notion of a
<emphasis>component</emphasis>. Components are stateful objects, usually EJBs, and an instance of a
component is associated with a context, and given a name in that context. <emphasis>Bijection</emphasis>
provides a mechanism for aliasing internal component names (instance variables) to contextual names, allowing
component trees to be dynamically assembled, and reassembled by Seam.
</para>
<para>
Let's start by describing the contexts built in to Seam.
</para>
<sect1>
<title>Seam contexts</title>
<para> Seam contexts are created and destroyed by the framework. The application does not control context
demarcation via explicit Java API calls. Context are usually implicit. In some cases, however, contexts are
demarcated via annotations. </para>
<para> The basic Seam contexts are: </para>
<itemizedlist>
<listitem>
<para> Stateless context </para>
</listitem>
<listitem>
<para> Event (i.e., request) context </para>
</listitem>
<listitem>
<para> Page context </para>
</listitem>
<listitem>
<para> Conversation context </para>
</listitem>
<listitem>
<para> Session context </para>
</listitem>
<listitem>
<para> Business process context </para>
</listitem>
<listitem>
<para> Application context </para>
</listitem>
</itemizedlist>
<para>
You will recognize some of these contexts from servlet and related specifications. However, two of them
might be new to you: <emphasis>conversation context</emphasis>, and <emphasis>business process
context</emphasis>. One reason state management in web applications is so fragile and error-prone is that
the three built-in contexts (request, session and application) are not especially meaningful from the point
of view of the business logic. A user login session, for example, is a fairly arbitrary construct in terms
of the actual application work flow. Therefore, most Seam components are scoped to the conversation or
business process contexts, since they are the contexts which are most meaningful in terms of the
application.
</para>
<para>
Let's look at each context in turn.
</para>
<sect2>
<title>Stateless context</title>
<para>
Components which are truly stateless (stateless session beans, primarily) always live in the stateless
context (which is basically the absence of a context since the instance Seam resolves is not stored).
Stateless components are not very interesting, and are arguably not very object-oriented. Nevertheless,
they do get developed and used and are thus an important part of any Seam application.
</para>
</sect2>
<sect2>
<title>Event context</title>
<para>
The event context is the "narrowest" stateful context, and is a generalization of the notion of the
web request context to cover other kinds of events. Nevertheless, the event context associated with the
lifecycle of a JSF request is the most important example of an event context, and the one you will work
with most often. Components associated with the event context are destroyed at the end of the request,
but their state is available and well-defined for at least the lifecycle of the request.
</para>
<para>
When you invoke a Seam component via RMI, or Seam Remoting, the event context is created and
destroyed just for the invocation.
</para>
</sect2>
<sect2>
<title>Page context</title>
<para>
The page context allows you to associate state with a particular instance of a rendered page. You can
initialize state in your event listener, or while actually rendering the page, and then have access to
it from any event that originates from that page. This is especially useful for functionality like
clickable lists, where the list is backed by changing data on the server side. The state is actually
serialized to the client, so this construct is extremely robust with respect to multi-window operation
and the back button.
</para>
</sect2>
<sect2>
<title>Conversation context</title>
<para>
The conversation context is a truly central concept in Seam. A <emphasis>conversation</emphasis> is a
unit of work from the point of view of the user. It might span several interactions with the user,
several requests, and several database transactions. But to the user, a conversation solves a single
problem. For example, "book hotel", "approve contract", "create order" are all conversations. You might
like to think of a conversation implementing a single "use case" or "user story", but the relationship
is not necessarily quite exact.
</para>
<para>
A conversation holds state associated with "what the user is doing now, in this window". A single
user may have multiple conversations in progress at any point in time, usually in multiple windows. The
conversation context allows us to ensure that state from the different conversations does not collide
and cause bugs.
</para>
<para>
It might take you some time to get used to thinking of applications in terms of conversations. But
once you get used to it, we think you'll love the notion, and never be able to not think in terms of
conversations again!
</para>
<para>
Some conversations last for just a single request. Conversations that span multiple requests must be
demarcated using annotations provided by Seam.
</para>
<para>
Some conversations are also <emphasis>tasks</emphasis>. A task is a conversation that is significant
in terms of a long-running business process, and has the potential to trigger a business process state
transition when it is successfully completed. Seam provides a special set of annotations for task
demarcation.
</para>
<para>
Conversations may be <emphasis>nested</emphasis>, with one conversation taking place "inside" a wider
conversation. This is an advanced feature.
</para>
<para>
Usually, conversation state is actually held by Seam in the servlet session between requests. Seam
implements configurable <emphasis>conversation timeout</emphasis>, automatically destroying inactive
conversations, and thus ensuring that the state held by a single user login session does not grow
without bound if the user abandons conversations.
</para>
<para>
Seam serializes processing of concurrent requests that take place in the same long-running
conversation context, in the same process.
</para>
<para>
Alternatively, Seam may be configured to keep conversational state in the client browser.
</para>
</sect2>
<sect2>
<title>Session context</title>
<para>
A session context holds state associated with the user login session. While there are some cases
where it is useful to share state between several conversations, we generally frown on the use of
session context for holding components other than global information about the logged in user.
</para>
<para>
In a JSR-168 portal environment, the session context represents the portlet session.
</para>
</sect2>
<sect2>
<title>Business process context</title>
<para>
The business process context holds state associated with the long running business process. This
state is managed and made persistent by the BPM engine (JBoss jBPM). The business process spans multiple
interactions with multiple users, so this state is shared between multiple users, but in a well-defined
manner. The current task determines the current business process instance, and the lifecycle of the
business process is defined externally using a <emphasis>process definition language</emphasis>, so
there are no special annotations for business process demarcation.
</para>
</sect2>
<sect2>
<title>Application context</title>
<para>
The application context is the familiar servlet context from the servlet spec. Application context is
mainly useful for holding static information such as configuration data, reference data or metamodels.
For example, Seam stores its own configuration and metamodel in the application context.
</para>
</sect2>
<sect2>
<title>Context variables</title>
<para>
A context defines a namespace, a set of <emphasis>context variables</emphasis>. These work much the
same as session or request attributes in the servlet spec. You may bind any value you like to a context
variable, but usually we bind Seam component instances to context variables.
</para>
<para>
So, within a context, a component instance is identified by the context variable name (this is
usually, but not always, the same as the component name). You may programmatically access a named
component instance in a particular scope via the <literal>Contexts</literal> class, which provides
access to several thread-bound instances of the <literal>Context</literal> interface:
</para>
<programlisting role="JAVA"><![CDATA[User user = (User) Contexts.getSessionContext().get("user");]]></programlisting>
<para>
You may also set or change the value associated with a name:
</para>
<programlisting role="JAVA"><![CDATA[Contexts.getSessionContext().set("user", user);]]></programlisting>
<para>
Usually, however, we obtain components from a context via injection, and put component instances into
a context via outjection.
</para>
</sect2>
<sect2>
<title>Context search priority</title>
<para>
Sometimes, as above, component instances are obtained from a particular known scope. Other times, all
stateful scopes are searched, in <emphasis>priority order</emphasis>. The order is as follows:
</para>
<itemizedlist>
<listitem>
<para> Event context </para>
</listitem>
<listitem>
<para> Page context </para>
</listitem>
<listitem>
<para> Conversation context </para>
</listitem>
<listitem>
<para> Session context </para>
</listitem>
<listitem>
<para> Business process context </para>
</listitem>
<listitem>
<para> Application context </para>
</listitem>
</itemizedlist>
<para>
You can perform a priority search by calling <literal>Contexts.lookupInStatefulContexts()</literal>.
Whenever you access a component by name from a JSF page, a priority search occurs.
</para>
</sect2>
<sect2 id="concurrency">
<title>Concurrency model</title>
<para>
Neither the servlet nor EJB specifications define any facilities for managing concurrent requests
originating from the same client. The servlet container simply lets all threads run concurrently and
leaves enforcing thread safeness to application code. The EJB container allows stateless components to be
accessed concurrently, and throws an exception if multiple threads access a stateful session bean.
</para>
<para>
This behavior might have been okay in old-style web applications which were based around
fine-grained, synchronous requests. But for modern applications which make heavy use of many
fine-grained, asynchronous (AJAX) requests, concurrency is a fact of life, and must be supported by the
programming model. Seam weaves a concurrency management layer into its context model.
</para>
<para>
The Seam session and application contexts are multithreaded. Seam will allow concurrent requests in a
context to be processed concurrently. The event and page contexts are by nature single threaded. The
business process context is strictly speaking multi-threaded, but in practice concurrency is
sufficiently rare that this fact may be disregarded most of the time. Finally, Seam enforces a
<emphasis>single thread per conversation per process</emphasis> model for the conversation context
by serializing concurrent requests in the same long-running conversation context.
</para>
<para>
Since the session context is multithreaded, and often contains volatile state, session scope
components are always protected by Seam from concurrent access so long as the Seam interceptors
are not disabled for that component. If interceptors are disabled, then any thread-safety that is
required must be implemented by the component itself. Seam serializes requests to session
scope JavaBeans by default (and detects and breaks any deadlocks that occur). This is
not the default behaviour for application scoped components however, since application scoped components
do not usually hold volatile state and because synchronization at the global level is
<emphasis>extremely</emphasis> expensive. However, you can force a serialized threading model on any
JavaBean component by adding the <literal>@Synchronized</literal> annotation.
</para>
<note>
<para>Seam 2.3 removed the serialization of Stateful
session beans by Seam synchronization interceptor
because stateful session beans are serialized by EJB 3.1
container by default .</para>
</note>
<para>
This concurrency model means that AJAX clients can safely use volatile session and conversational
state, without the need for any special work on the part of the developer.
</para>
<warning>
<para>
Be warned that Statefull session Beans are not serialized by Seam anymore.
Serialization of Statefull session beans are controlled by EJB container,
so there is no need for Seam to duplicate that. So @Synchronized annotation
is ignored on Statefull session beans.
</para>
</warning>
</sect2>
</sect1>
<sect1>
<title>Seam components</title>
<para>
Seam components are POJOs (Plain Old Java Objects). In particular, they are JavaBeans or EJB 3.0
enterprise beans. While Seam does not require that components be EJBs and can even be used without an EJB
3.0 compliant container, Seam was designed with EJB 3.0 in mind and includes deep integration with EJB 3.0.
Seam supports the following <emphasis>component types</emphasis>.
</para>
<itemizedlist>
<listitem>
<para> EJB 3.0 stateless session beans </para>
</listitem>
<listitem>
<para> EJB 3.0 stateful session beans </para>
</listitem>
<listitem>
<para> EJB 3.0 entity beans (i.e., JPA entity classes)</para>
</listitem>
<listitem>
<para> JavaBeans </para>
</listitem>
<listitem>
<para> EJB 3.0 message-driven beans </para>
</listitem>
<listitem>
<para> Spring beans (see <xref linkend="spring"/>)</para>
</listitem>
</itemizedlist>
<sect2>
<title>Stateless session beans</title>
<para>
Stateless session bean components are not able to hold state across multiple invocations. Therefore,
they usually work by operating upon the state of other components in the various Seam contexts. They may
be used as JSF action listeners, but cannot provide properties to JSF components for display.
</para>
<para>
Stateless session beans always live in the stateless context.
</para>
<para>
Stateless session beans can be accessed concurrently as a new instance is used for each request.
Assigning the instance to the request is the responsibility of the EJB3 container (normally instances
will be allocated from a reusable pool meaning that you may find any instance variables contain data
from previous uses of the bean).
</para>
<para>
Stateless session beans are the least interesting kind of Seam component.
</para>
<para>
Seam stateless session bean components may be instantiated using <literal>Component.getInstance()</literal>
or <literal>@In(create=true)</literal>. They should not be directly instantiated via JNDI lookup
or the <literal>new</literal> operator.
</para>
</sect2>
<sect2>
<title>Stateful session beans</title>
<para>
Stateful session bean components are able to hold state not only across multiple invocations of the
bean, but also across multiple requests. Application state that does not belong in the database should
usually be held by stateful session beans. This is a major difference between Seam and many other web
application frameworks. Instead of sticking information about the current conversation directly in the
<literal>HttpSession</literal>, you should keep it in instance variables of a stateful session bean
that is bound to the conversation context. This allows Seam to manage the lifecycle of this state for
you, and ensure that there are no collisions between state relating to different concurrent
conversations.
</para>
<para>
Stateful session beans are often used as JSF action listener, and as backing beans that provide
properties to JSF components for display or form submission.
</para>
<para>
By default, stateful session beans are bound to the conversation context. They may never be bound to
the page or stateless contexts.
</para>
<para>
Concurrent requests to session-scoped stateful session beans are not serialized by Seam as long
as EJB 3.1 has changed that. This is a difference in comparison to previous Seam 2.2.x.
</para>
<para>
Seam stateful session bean components may be instantiated using <literal>Component.getInstance()</literal>
or <literal>@In(create=true)</literal>. They should not be directly instantiated via JNDI lookup
or the <literal>new</literal> operator.
</para>
</sect2>
<sect2>
<title>Entity beans</title>
<para>
Entity beans may be bound to a context variable and function as a seam component. Because entities
have a persistent identity in addition to their contextual identity, entity instances are usually bound
explicitly in Java code, rather than being instantiated implicitly by Seam.
</para>
<para>
Entity bean components do not support bijection or context demarcation. Nor does invocation of an
entity bean trigger validation.
</para>
<para>
Entity beans are not usually used as JSF action listeners, but do often function as backing beans
that provide properties to JSF components for display or form submission. In particular, it is common to
use an entity as a backing bean, together with a stateless session bean action listener to implement
create/update/delete type functionality.
</para>
<para>
By default, entity beans are bound to the conversation context. They may never be bound to the
stateless context.
</para>
<para>
Note that it in a clustered environment is somewhat less efficient to bind an entity bean directly to
a conversation or session scoped Seam context variable than it would be to hold a reference to the
entity bean in a stateful session bean. For this reason, not all Seam applications define entity beans
to be Seam components.
</para>
<para>
Seam entity bean components may be instantiated using <literal>Component.getInstance()</literal>,
<literal>@In(create=true)</literal> or directly using the <literal>new</literal> operator.
</para>
</sect2>
<sect2>
<title>JavaBeans</title>
<para>
JavaBeans may be used just like a stateless or stateful session bean. However, they do not provide
the functionality of a session bean (declarative transaction demarcation, declarative security,
efficient clustered state replication, EJB 3.0 persistence, timeout methods, etc).
</para>
<para>
In a later chapter, we show you how to use Seam and Hibernate without an EJB container. In this use
case, components are JavaBeans instead of session beans. Note, however, that in many application servers
it is somewhat less efficient to cluster conversation or session scoped Seam JavaBean components than it
is to cluster stateful session bean components.
</para>
<para>
By default, JavaBeans are bound to the event context.
</para>
<para>
Concurrent requests to session-scoped JavaBeans are always serialized by Seam.
</para>
<para>
Seam JavaBean components may be instantiated using <literal>Component.getInstance()</literal>
or <literal>@In(create=true)</literal>. They should not be directly instantiated using the
<literal>new</literal> operator.
</para>
</sect2>
<sect2>
<title>Message-driven beans</title>
<para>
Message-driven beans may function as a seam component. However, message-driven beans are called quite
differently to other Seam components - instead of invoking them via the context variable, they listen
for messages sent to a JMS queue or topic.
</para>
<para>
Message-driven beans may not be bound to a Seam context. Nor do they have access to the session or
conversation state of their "caller". However, they do support bijection and some other Seam
functionality.
</para>
<para>
Message-driven beans are never instantiated by the application. They are instantiated by the EJB
container when a message is received.
</para>
</sect2>
<sect2>
<title>Interception</title>
<para>
In order to perform its magic (bijection, context demarcation, validation, etc), Seam must intercept
component invocations. For JavaBeans, Seam is in full control of instantiation of the component, and no
special configuration is needed. For entity beans, interception is not required since bijection and
context demarcation are not defined. For session beans, we must register an EJB interceptor for the
session bean component. We could use an annotation, as follows:
</para>
<programlisting role="JAVA"><![CDATA[@Stateless
@Interceptors(SeamInterceptor.class)
public class LoginAction implements Login {
...
}]]></programlisting>
<para>
But a much better way is to define the interceptor in <literal>ejb-jar.xml</literal>.
</para>
<programlisting role="XML"><![CDATA[<interceptors>
<interceptor>
<interceptor-class>org.jboss.seam.ejb.SeamInterceptor</interceptor-class>
</interceptor>
</interceptors>
<assembly-descriptor>
<interceptor-binding>
<ejb-name>*</ejb-name>
<interceptor-class>org.jboss.seam.ejb.SeamInterceptor</interceptor-class>
</interceptor-binding>
</assembly-descriptor>]]></programlisting>
</sect2>
<sect2>
<title>Component names</title>
<para>
All seam components need a name. We can assign a name to a component using the
<literal>@Name</literal> annotation:
</para>
<programlisting role="JAVA"><![CDATA[@Name("loginAction")
@Stateless
public class LoginAction implements Login {
...
}]]></programlisting>
<para>
This name is the <emphasis>seam component name</emphasis> and is not related to any other name
defined by the EJB specification. However, seam component names work just like JSF managed bean names
and you can think of the two concepts as identical.
</para>
<para>
<literal>@Name</literal> is not the only way to define a component name, but we always need
to specify the name <emphasis>somewhere</emphasis>. If we don't, then none of the other
Seam annotations will function.
</para>
<para>
Whenever Seam instantiates a component, it binds the new instance to a variable in the scope configured
for the component that matches the component name. This behavior is identical to how JSF managed beans
work, except that Seam allows you to configure this mapping using annotations rather than XML. You can
also programmatically bind a component to a context variable. This is useful if a particular component
serves more than one role in the system. For example, the currently logged in <literal>User</literal>
might be bound to the <literal>currentUser</literal> session context variable, while a
<literal>User</literal> that is the subject of some administration functionality might be bound to the
<literal>user</literal> conversation context variable. Be careful, though, because through a
programmatic assignment, it's possible to overwrite a context variable that has a reference to a Seam
component, potentially confusing matters. </para>
<para>
For very large applications, and for built-in seam components, qualified component names are often used
to avoid naming conflicts.
</para>
<programlisting role="JAVA"><![CDATA[@Name("com.jboss.myapp.loginAction")
@Stateless
public class LoginAction implements Login {
...
}]]></programlisting>
<para>
We may use the qualified component name both in Java code and in JSF's expression language:
</para>
<programlisting role="XHTML"><![CDATA[<h:commandButton type="submit" value="Login"
action="#{com.jboss.myapp.loginAction.login}"/>]]></programlisting>
<para>
Since this is noisy, Seam also provides a means of aliasing a qualified name to a simple name. Add a
line like this to the <literal>components.xml</literal> file:
</para>
<programlisting role="XML"><![CDATA[<factory name="loginAction" scope="STATELESS" value="#{com.jboss.myapp.loginAction}"/>]]></programlisting>
<para>
All of the built-in Seam components have qualified names but can be accessed through
their unqualified names due to the namespace import feature of Seam.
The <literal>components.xml</literal> file included in the Seam JAR defines the following
namespaces.
</para>
<programlisting role="XML"><components xmlns="http://jboss.org/schema/seam/components">
<import>org.jboss.seam.core</import>
<import>org.jboss.seam.cache</import>
<import>org.jboss.seam.transaction</import>
<import>org.jboss.seam.framework</import>
<import>org.jboss.seam.web</import>
<import>org.jboss.seam.faces</import>
<import>org.jboss.seam.international</import>
<import>org.jboss.seam.theme</import>
<import>org.jboss.seam.pageflow</import>
<import>org.jboss.seam.bpm</import>
<import>org.jboss.seam.jms</import>
<import>org.jboss.seam.mail</import>
<import>org.jboss.seam.security</import>
<import>org.jboss.seam.security.management</import>
<import>org.jboss.seam.security.permission</import>
<import>org.jboss.seam.captcha</import>
<import>org.jboss.seam.excel.exporter</import>
<!-- ... --->
</components>
</programlisting>
<para>
When attempting to resolve an unqualified name, Seam will check each of those namespaces, in order.
You can include additional namespaces in your application's <literal>components.xml</literal> file
for application-specific namespaces.
</para>
</sect2>
<sect2>
<title>Defining the component scope</title>
<para>
We can override the default scope (context) of a component using the <literal>@Scope</literal>
annotation. This lets us define what context a component instance is bound to, when it is instantiated
by Seam.
</para>
<programlisting role="JAVA"><![CDATA[@Name("user")
@Entity
@Scope(SESSION)
public class User {
...
}]]></programlisting>
<para>
<literal>org.jboss.seam.ScopeType</literal> defines an enumeration of possible scopes.
</para>
</sect2>
<sect2>
<title>Components with multiple roles</title>
<para>
Some Seam component classes can fulfill more than one role in the system. For example, we often have
a <literal>User</literal> class which is usually used as a session-scoped component representing the
current user but is used in user administration screens as a conversation-scoped component. The
<literal>@Role</literal> annotation lets us define an additional named role for a component, with a
different scope — it lets us bind the same component class to different context variables. (Any
Seam component <emphasis>instance</emphasis> may be bound to multiple context variables, but this lets
us do it at the class level, and take advantage of auto-instantiation.)
</para>
<programlisting role="JAVA"><![CDATA[@Name("user")
@Entity
@Scope(CONVERSATION)
@Role(name="currentUser", scope=SESSION)
public class User {
...
}]]></programlisting>
<para>
The <literal>@Roles</literal> annotation lets us specify as many additional roles as we like.
</para>
<programlisting role="JAVA"><![CDATA[@Name("user")
@Entity
@Scope(CONVERSATION)
@Roles({@Role(name="currentUser", scope=SESSION),
@Role(name="tempUser", scope=EVENT)})
public class User {
...
}]]></programlisting>
</sect2>
<sect2>
<title>Built-in components</title>
<para>
Like many good frameworks, Seam eats its own dogfood and is implemented mostly as a set of built-in
Seam interceptors (see later) and Seam components. This makes it easy for applications to interact with
built-in components at runtime or even customize the basic functionality of Seam by replacing the
built-in components with custom implementations. The built-in components are defined in the Seam
namespace <literal>org.jboss.seam.core</literal> and the Java package of the same name.
</para>
<para>
The built-in components may be injected, just like any Seam components, but they also provide
convenient static <literal>instance()</literal> methods:
</para>
<programlisting role="JAVA"><![CDATA[FacesMessages.instance().add("Welcome back, #{user.name}!");]]></programlisting>
</sect2>
</sect1>
<sect1>
<title>Bijection</title>
<para>
<emphasis>Dependency injection</emphasis> or <emphasis>inversion of control</emphasis> is by now a familiar
concept to most Java developers. Dependency injection allows a component to obtain a reference to another
component by having the container "inject" the other component to a setter method or instance variable. In
all dependency injection implementations that we have seen, injection occurs when the component is
constructed, and the reference does not subsequently change for the lifetime of the component instance. For
stateless components, this is reasonable. From the point of view of a client, all instances of a particular
stateless component are interchangeable. On the other hand, Seam emphasizes the use of stateful components.
So traditional dependency injection is no longer a very useful construct. Seam introduces the notion of
<emphasis>bijection</emphasis> as a generalization of injection. In contrast to injection, bijection is:
</para>
<itemizedlist>
<listitem>
<para>
<emphasis>contextual</emphasis> - bijection is used to assemble stateful components from various
different contexts (a component from a "wider" context may even have a reference to a component from
a "narrower" context)
</para>
</listitem>
<listitem>
<para>
<emphasis>bidirectional</emphasis> - values are injected from context variables into attributes of
the component being invoked, and also <emphasis>outjected</emphasis> from the component attributes
back out to the context, allowing the component being invoked to manipulate the values of contextual
variables simply by setting its own instance variables
</para>
</listitem>
<listitem>
<para>
<emphasis>dynamic</emphasis> - since the value of contextual variables changes over time, and since
Seam components are stateful, bijection takes place every time a component is invoked
</para>
</listitem>
</itemizedlist>
<para>
In essence, bijection lets you alias a context variable to a component instance variable, by specifying
that the value of the instance variable is injected, outjected, or both. Of course, we use annotations to
enable bijection.
</para>
<para>
The <literal>@In</literal> annotation specifies that a value should be injected, either into an instance
variable:
</para>
<programlisting role="JAVA"><![CDATA[@Name("loginAction")
@Stateless
public class LoginAction implements Login {
@In User user;
...
}]]></programlisting>
<para>
or into a setter method:
</para>
<programlisting role="JAVA"><![CDATA[@Name("loginAction")
@Stateless
public class LoginAction implements Login {
User user;
@In
public void setUser(User user) {
this.user=user;
}
...
}]]></programlisting>
<para>
By default, Seam will do a priority search of all contexts, using the name of the property or instance
variable that is being injected. You may wish to specify the context variable name explicitly, using, for
example, <literal>@In("currentUser")</literal>.
</para>
<para>
If you want Seam to create an instance of the component when there is no existing component instance
bound to the named context variable, you should specify <literal>@In(create=true)</literal>. If the value is
optional (it can be null), specify <literal>@In(required=false)</literal>.
</para>
<para>
For some components, it can be repetitive to have to specify <literal>@In(create=true)</literal> everywhere
they are used. In such cases, you can annotate the component <literal>@AutoCreate</literal>, and then it
will always be created, whenever needed, even without the explicit use of <literal>create=true</literal>.
</para>
<para>
You can even inject the value of an expression:
</para>
<programlisting role="JAVA"><![CDATA[@Name("loginAction")
@Stateless
public class LoginAction implements Login {
@In("#{user.username}") String username;
...
}]]></programlisting>
<para>
Injected values are disinjected (i.e., set to <literal>null</literal>) immediately after method
completion and outjection.
</para>
<para>
(There is much more information about component lifecycle and injection in the next chapter.)
</para>
<para>
The <literal>@Out</literal> annotation specifies that an attribute should be outjected, either from an
instance variable:
</para>
<programlisting role="JAVA"><![CDATA[@Name("loginAction")
@Stateless
public class LoginAction implements Login {
@Out User user;
...
}]]></programlisting>
<para>
or from a getter method:
</para>
<programlisting role="JAVA"><![CDATA[@Name("loginAction")
@Stateless
public class LoginAction implements Login {
User user;
@Out
public User getUser() {
return user;
}
...
}]]></programlisting>
<para>
An attribute may be both injected and outjected:
</para>
<programlisting role="JAVA"><![CDATA[@Name("loginAction")
@Stateless
public class LoginAction implements Login {
@In @Out User user;
...
}]]></programlisting>
<para>
or:
</para>
<programlisting role="JAVA"><![CDATA[@Name("loginAction")
@Stateless
public class LoginAction implements Login {
User user;
@In
public void setUser(User user) {
this.user=user;
}
@Out
public User getUser() {
return user;
}
...
}]]></programlisting>
</sect1>
<sect1>
<title>Lifecycle methods</title>
<para>
Session bean and entity bean Seam components support all the usual EJB 3.0 lifecycle callback
(<literal>@PostConstruct</literal>, <literal>@PreDestroy</literal>, etc). But Seam also supports
the use of any of these callbacks with JavaBean components. However, since these annotations are
not available in a J2EE environment, Seam defines two additional component lifecycle callbacks,
equivalent to <literal>@PostConstruct</literal> and <literal>@PreDestroy</literal>.
</para>
<para>
The <literal>@Create</literal> method is called after Seam instantiates a component.
Components may define only one <literal>@Create</literal> method.
</para>
<para>
The <literal>@Destroy</literal> method is called when the context that the Seam component is bound to
ends. Components may define only one <literal>@Destroy</literal> method.
</para>
<para>
In addition, stateful session bean components <emphasis>must</emphasis> define a method with no parameters
annotated <literal>@Remove</literal>. This method is called by Seam when the context ends.
</para>
<para>
Finally, a related annotation is the <literal>@Startup</literal> annotation, which may be applied to any
application or session scoped component. The <literal>@Startup</literal> annotation tells Seam to
instantiate the component immediately, when the context begins, instead of waiting until it is first
referenced by a client. It is possible to control the order of instantiation of startup components by
specifying <literal>@Startup(depends={....})</literal>.
</para>
</sect1>
<sect1>
<title>Conditional installation</title>
<para>
The <literal>@Install</literal> annotation lets you control conditional installation of components that
are required in some deployment scenarios and not in others. This is useful if:
</para>
<itemizedlist>
<listitem>
<para>
You want to mock out some infrastructural component in tests.
</para>
</listitem>
<listitem>
<para>
You want change the implementation of a component in certain
deployment scenarios.
</para>
</listitem>
<listitem>
<para>
You want to install some components only if their dependencies are
available (useful for framework authors).
</para>
</listitem>
</itemizedlist>
<para>
<literal>@Install</literal> works by letting you specify <emphasis>precedence</emphasis>
and <emphasis>dependencies</emphasis>.
</para>
<para>
The precedence of a component is a number that Seam uses to decide which component to
install when there are multiple classes with the same component name in the classpath.
Seam will choose the component with the higher precedence. There are some predefined
precedence values (in ascending order):
</para>
<orderedlist>
<listitem>
<para>
<literal>BUILT_IN</literal> — the lowest precedence components are
the components built in to Seam.
</para>
</listitem>
<listitem>
<para>
<literal>FRAMEWORK</literal> — components defined by third-party
frameworks may override built-in components, but are overridden by
application components.
</para>
</listitem>
<listitem>
<para>
<literal>APPLICATION</literal> — the default precedence. This is
appropriate for most application components.
</para>
</listitem>
<listitem>
<para>
<literal>DEPLOYMENT</literal> — for application components which
are deployment-specific.
</para>
</listitem>
<listitem>
<para>
<literal>MOCK</literal> — for mock objects used in testing.
</para>
</listitem>
</orderedlist>
<para>
Suppose we have a component named <literal>messageSender</literal> that talks to
a JMS queue.
</para>
<programlisting role="JAVA"><![CDATA[@Name("messageSender")
public class MessageSender {
public void sendMessage() {
//do something with JMS
}
}]]></programlisting>
<para>
In our unit tests, we don't have a JMS queue available, so we would like to stub
out this method. We'll create a <emphasis>mock</emphasis> component that exists
in the classpath when unit tests are running, but is never deployed with the
application:
</para>
<programlisting role="JAVA"><![CDATA[@Name("messageSender")
@Install(precedence=MOCK)
public class MockMessageSender extends MessageSender {
public void sendMessage() {
//do nothing!
}
}]]></programlisting>
<para>
The <literal>precedence</literal> helps Seam decide which version to use when it finds
both components in the classpath.
</para>
<para>
This is nice if we are able to control exactly which classes are in the classpath. But
if I'm writing a reusable framework with many dependencies, I don't want to have to
break that framework across many jars. I want to be able to decide which components
to install depending upon what other components are installed, and upon what classes
are available in the classpath. The <literal>@Install</literal> annotation also
controls this functionality. Seam uses this mechanism internally to enable conditional
installation of many of the built-in components. However, you probably won't need to
use it in your application.