Author: laubai
Date: 2009-11-24 03:51:59 -0500 (Tue, 24 Nov 2009)
New Revision: 11674
Modified:
tags/JBPAPP_4_3_CP07_FP_CR1a/doc/Seam_Reference_Guide/en-US/Tutorial.xml
Log:
Edited the Tutorial chapter.
Modified: tags/JBPAPP_4_3_CP07_FP_CR1a/doc/Seam_Reference_Guide/en-US/Tutorial.xml
===================================================================
--- tags/JBPAPP_4_3_CP07_FP_CR1a/doc/Seam_Reference_Guide/en-US/Tutorial.xml 2009-11-24
08:09:15 UTC (rev 11673)
+++ tags/JBPAPP_4_3_CP07_FP_CR1a/doc/Seam_Reference_Guide/en-US/Tutorial.xml 2009-11-24
08:51:59 UTC (rev 11674)
@@ -97,7 +97,7 @@
<emphasis>validation</emphasis> declaratively, via
annotations. It also needs some extra
annotations that define the class as a Seam component. </para>
<!-- Can't use code hightlighting with callouts -->
- <example>
+
<formalpara><title>User.java Example</title>
<para>
<programlisting role="JAVA"><![CDATA[@Entity
@@ -198,7 +198,7 @@
</orderedlist>
</para>
</formalpara>
-</example>
+
<para> The most important things to notice in this example are
the <literal>@Name</literal> and
<literal>@Scope</literal> annotations. These
annotations establish that this class is a Seam component. </para>
<para> We'll see below that the properties of our
<literal>User</literal> class are bound
@@ -214,7 +214,7 @@
<section>
<title>The stateless session bean class:
<literal>RegisterAction.java</literal></title>
- <para> Most Seam application use session beans as JSF action
listeners (you can use JavaBeans instead if
+ <para> Most Seam applications use session beans as JSF action
listeners (you can use JavaBeans instead if
you like). </para>
<para> We have exactly one JSF action in our application, and one
session bean method attached to it. In
this case, we'll use a stateless session bean, since all the
state associated with our action is
@@ -392,18 +392,9 @@
<section>
<title>The Seam component deployment descriptor:
<literal>components.xml</literal></title>
- <para> If you've used many Java frameworks before, you'll
be used to having to declare all your
- component classes in some kind of XML file that gradually grows more
and more unmanageable as your
- project matures. You'll be relieved to know that Seam does not
require that application components
- be accompanied by XML. Most Seam applications require a very small
amount of XML that does not grow
- very much as the project gets bigger. </para>
+ <para> If you have used Java frameworks previously, you will be
used to declaring your component classes in an XML file. You have probably also noticed
that as a project matures, these XML files tend to become unmanageable. Fortunately, Seam
does not require application components to be accompanied by XML. Most Seam applications
require only a small amount of XML, which does not tend to increase in size as projects
expand. </para>
- <para> Nevertheless, it is often useful to be able to provide for
<emphasis>some</emphasis> external
- configuration of <emphasis>some</emphasis> components
(particularly the components built in to
- Seam). You have a couple of options here, but the most flexible
option is to provide this
- configuration in a file called
<literal>components.xml</literal>, located in the
- <literal>WEB-INF</literal> directory. We'll use the
<literal>components.xml</literal> file to tell
- Seam how to find our EJB components in JNDI: </para>
+ <para> However, it is often useful to be able to provide for some
external configuration of some components, particularly the components that are built into
Seam. The most flexible option, here, is to provide this configuration in a file called
<filename>components.xml</filename>, located in the
<filename>WEB-INF</filename> directory. The
<filename>components.xml</filename> file can be used to tell Seam how to find
our EJB components in JNDI: </para>
<example>
<title></title>
<programlisting role="XML">
@@ -504,17 +495,12 @@
</example>
- <para> Note that we don't need
- any JSF managed bean declarations! Our managed beans are annotated
Seam components. In Seam applications,
- the <literal>faces-config.xml</literal> is used much less
often than in plain JSF. </para>
+ <para> Note that JSF managed bean declarations are unnecessary
because the managed beans are annotated Seam components. In Seam applications,
<filename>faces-config.xml</filename> is used much less often than in plain
JSF. Here, we use it simply to enable Facelets (and not JSP) as the view handler.
+ </para>
- <para> In fact, once you have all the basic descriptors set up, the
<emphasis>only</emphasis> XML you
- need to write as you add new functionality to a Seam application is
orchestration: navigation rules
- or jBPM process definitions. Seam takes the view that
<emphasis>process flow</emphasis> and
- <emphasis>configuration data</emphasis> are the only
things that truly belong in XML. </para>
+ <para> Once you have set up all the basic descriptors, the only XML
you need write to add functionality to a Seam application will be for orchestration:
navigation rules or jBPM process definitions. Seam operates on the principle that process
flow and configuration data are all that truly belongs in XML. </para>
- <para> In this simple example, we don't even need a navigation
rule, since we decided to embed the view
- id in our action code. </para>
+ <para> The previous example does not require a navigation rule,
since the view ID was embedded in our action code. </para>
</section>
@@ -579,7 +565,7 @@
<title>The view: <literal>register.xhtml</literal> and
<literal>registered.xhtml</literal></title>
<para> The view pages for a Seam application could be implemented
using any technology that supports
- JSF. In this example we use Facelets, because we think it's
better than JSP.</para>
+ JSF. This example uses Facelets.</para>
<example>
<title></title>
@@ -638,9 +624,6 @@
</example>
- <para> This is a boring old Facelets page using some embedded EL.
There is nothing specific to Seam
- here. </para>
-
</section>
<section>
@@ -681,8 +664,6 @@
<para> This deployment descriptor links modules in the enterprise
archive and binds the web application
to the context root
<literal>/seam-registration</literal>. </para>
- <para> We've now seen <emphasis>all</emphasis> the
files in the entire application! </para>
-
</section>
</section>
@@ -813,7 +794,7 @@
<para> But <literal>MessageManagerBean</literal> is
also responsible for fetching the list of messages
the first time we navigate to the message list page. There are
various ways the user could navigate
- to the page, and not all of them are preceded by a JSF
action—the user might have
+ to the page, and not all of them are preceded by a JSF action
— the user might have
bookmarked the page, for example. So the job of fetching the message
list takes place in a Seam
<emphasis>factory method</emphasis>, instead of in an
action listener method. </para>
@@ -934,12 +915,11 @@
public void destroy();
}</programlisting>
- <para> From now on, we won't show local interfaces in our code
examples. </para>
- <para> Let's skip over
<literal>components.xml</literal>,
<literal>persistence.xml</literal>,
+ <para> From this point, local interfaces are no longer shown in
these code examples.
+ <literal>components.xml</literal>,
<literal>persistence.xml</literal>,
<literal>web.xml</literal>,
<literal>ejb-jar.xml</literal>,
<literal>faces-config.xml</literal>
- and <literal>application.xml</literal> since they are
much the same as the previous example, and go
- straight to the JSP. </para>
+ and <literal>application.xml</literal> operate in a
similar fashion to the previous example and to directly to the JSP. </para>
</section>
@@ -1055,8 +1035,8 @@
<section>
<title>Understanding the code</title>
<para> The center of this example is the jBPM process definition. There
are also two JSPs and two trivial
- JavaBeans (There was no reason to use session beans, since they do not
access the database, or have any
- other transactional behavior). Let's start with the process
definition: </para>
+ JavaBeans. (There was no reason to use session beans, since they do not
access the database, or have any
+ other transactional behavior.) Let's start with the process
definition: </para>
<!-- Can't use code hightlighting with callouts -->
<formalpara><title>todo.jpdl.xml Example</title>
<para>
@@ -1531,7 +1511,7 @@
</imageobject>
</mediaobject>
- <para> Now that we have seen the pageflow, it is very, very easy to
understand the rest of the application! </para>
+ <para> Now that we have seen the pageflow, it is easy to understand the
rest of the application. </para>
<para> Here is the main page of the application,
<literal>numberGuess.jspx</literal>: </para>
@@ -1647,7 +1627,7 @@
</example>
- <para> As is <literal>lose.jspx</literal> (which I
can't be bothered copy/pasting). Finally, the JavaBean
+ <para><filename>lose.jspx</filename> is also as expected.
Finally, the JavaBean
Seam component: </para>
<!-- Can't use code hightlighting with callouts -->
<formalpara><title>NumberGuess.java Example</title>
@@ -1786,7 +1766,7 @@
</programlisting>
- <para> As you can see, this Seam component is pure business logic!
It doesn't need to know anything at all
+ <para> As you can see, this Seam component is pure business logic.
It doesn't need to know anything at all
about the user interaction flow. This makes the component potentially
more reuseable. </para>
</section>
@@ -1849,50 +1829,60 @@
</mediaobject>
</screenshot>
- <para> The booking application uses JSF, EJB 3.0 and Seam, together
with Facelets for the view. There is
- also a port of this application to JSF, Facelets, Seam, JavaBeans and
Hibernate3. </para>
+ <para> The booking application uses JSF, EJB 3.0 and Seam, together
with Facelets for the view. There is also a port of this application to JSF, Facelets,
Seam, JavaBeans and Hibernate3. </para>
- <para> One of the things you'll notice if you play with this
application for long enough is that it is
- extremely <emphasis>robust</emphasis>. You can play with back
buttons and browser refresh and opening
- multiple windows and entering nonsensical data as much as you like and
you will find it very difficult
- to make the application crash. You might think that we spent weeks
testing and fixing bugs to achive
- this. Actually, this is not the case. Seam was designed to make it very
straightforward to build robust
- web applications and a lot of robustness that you are probably used to
having to code yourself comes
- naturally and automatically with Seam. </para>
- <para> As you browse the sourcecode of the example application, and
learn how the application works, observe
- how the declarative state management and integrated validation has been
used to achieve this robustness. </para>
+ <para> One of the things you will notice about this application is that
it is extremely robust. You can open multiple windows, use the back and browser refresh
buttons, and enter nonsensical data, but the application is difficult to crash. Seam was
designed to make building robust web applications straightforward, so robustness that
would previously be hand-coded comes naturally and automatically with Seam. </para>
+
+ <para> As you browse the source code of the example application and
learn how the application works, pay particular attention to the way the declarative state
management and integrated validation has been used to achieve this robustness.
</para>
</section>
<section>
<title>Overview of the booking example</title>
- <para> The project structure is identical to the previous one, to
install and deploy this application,
+ <para> The project structure is identical to the previous one. To
install and deploy this application,
please refer to <xref linkend="try-examples"/>. Once
you've successfully started the application, you
can access it by pointing your browser to <ulink
url="http://localhost:8080/seam-booking/">
<literal>http://localhost:8080/seam-booking/</literal>
</ulink>
</para>
- <para> Just nine classes (plus six session beans local interfaces)
where used to implement this application.
- Six session bean action listeners contain all the business logic for the
listed features. </para>
+ <para> The application uses six session beans to implement the business
logic for the following features: </para>
- <itemizedlist>
+ <itemizedlist>
<listitem>
- <para><literal>BookingListAction</literal>
retrieves existing bookings for the currently logged in user. </para>
+ <para>
+ <literal>AuthenticatorAction</literal> provides the
login authentication logic.
+ </para>
</listitem>
- <listitem>
- <para><literal>ChangePasswordAction</literal>
updates the password of the currently logged in user.</para>
+ <listitem>
+ <para>
+ <literal>BookingListAction</literal> retrieves
existing bookings for the currently logged in user.
+ </para>
</listitem>
- <listitem>
- <para><literal>HotelBookingAction</literal>
implements the core functionality of the application: hotel
- room searching, selection, booking and booking confirmation. This
functionality is implemented as a
- <emphasis>conversation</emphasis>, so this is the
most interesting class in the application. </para></listitem>
- <listitem>
- <para><literal>RegisterAction</literal> registers a
new system user.</para>
+ <listitem>
+ <para>
+ <literal>ChangePasswordAction</literal> updates the
password of the currently logged in user.
+ </para>
</listitem>
+ <listitem>
+ <para>
+ <literal>HotelBookingAction</literal> implements
booking and confirmation functionality. This is implemented as a
<emphasis>conversation</emphasis>, so this is one of the more important
classes in the application.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>HotelSearchingAction</literal> implements
the hotel search functionality.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>RegisterAction</literal> registers a new
system user.
+ </para>
+ </listitem>
</itemizedlist>
+
<para> Three entity beans implement the application's persistent
domain model. </para>
<itemizedlist>
@@ -1909,66 +1899,36 @@
<section>
<title>Understanding Seam conversations</title>
- <para> We encourage you browse the sourcecode at your pleasure. In this
tutorial we'll concentrate upon one
- particular piece of functionality: hotel search, selection, booking and
confirmation. From the point of
- view of the user, everything from selecting a hotel to confirming a
booking is one continuous unit of
- work, a <emphasis>conversation</emphasis>. Searching,
however, is <emphasis>not</emphasis> part of the
- conversation. The user can select multiple hotels from the same search
results page, in different
- browser tabs. </para>
- <para> Most web application architectures have no first class construct
to represent a conversation. This
- causes enormous problems managing state associated with the conversation.
Usually, Java web applications
- use a combination of two techniques: first, some state is thrown into
the
- <literal>HttpSession</literal>; second, persistable state is
flushed to the database after every
- request, and reconstructed from the database at the beginning of each new
request. </para>
- <para> Since the database is the least scalable tier, this often
results in an utterly unacceptable lack of
- scalability. Added latency is also a problem, due to the extra traffic to
and from the database on every
- request. To reduce this redundant traffic, Java applications often
introduce a data (second-level) cache
- that keeps commonly accessed data between requests. This cache is
necessarily inefficient, because
- invalidation is based upon an LRU policy instead of being based upon when
the user has finished working
- with the data. Furthermore, because the cache is shared between many
concurrent transactions, we've
- introduced a whole raft of problem's associated with keeping the
cached state consistent with the
- database. </para>
- <para> Now consider the state held in the
<literal>HttpSession</literal>. By very careful programming, we
- might be able to control the size of the session data. This is a lot more
difficult than it sounds,
- since web browsers permit ad hoc non-linear navigation. But suppose we
suddenly discover a system
- requirement that says that a user is allowed to have
<emphasis>mutiple concurrent
- conversations</emphasis>, halfway through the development of the
system (this has happened to me).
- Developing mechanisms to isolate session state associated with different
concurrent conversations, and
- incorporating failsafes to ensure that conversation state is destroyed
when the user aborts one of the
- conversations by closing a browser window or tab is not for the faint
hearted (I've implemented this
- stuff twice so far, once for a client application, once for Seam, but
I'm famously psychotic). </para>
- <para> Now there is a better way. </para>
- <para> Seam introduces the <emphasis>conversation
context</emphasis> as a first class construct. You can
- safely keep conversational state in this context, and be assured that it
will have a well-defined
- lifecycle. Even better, you won't need to be continually pushing data
back and forth between the
- application server and the database, since the conversation context is a
natural cache of data that the
- user is currently working with. </para>
- <para> Usually, the components we keep in the conversation context are
stateful session beans. (We can also
- keep entity beans and JavaBeans in the conversation context.) There is an
ancient canard in the Java
- community that stateful session beans are a scalability killer. This may
have been true in 1998 when
- WebFoobar 1.0 was released. It is no longer true today. Application
servers like JBoss AS have extremely
- sophisticated mechanisms for stateful session bean state replication.
(For example, the JBoss EJB3
- container performs fine-grained replication, replicating only those bean
attribute values which actually
- changed.) Note that all the traditional technical arguments for why
stateful beans are inefficient apply
- equally to the <literal>HttpSession</literal>, so the
practice of shifting state from business tier
- stateful session bean components to the web session to try and improve
performance is unbelievably
- misguided. It is certainly possible to write unscalable applications
using stateful session beans, by
- using stateful beans incorrectly, or by using them for the wrong thing.
But that doesn't mean you should
- <emphasis>never</emphasis> use them. Anyway, Seam guides
you toward a safe usage model. Welcome to
- 2005. </para>
- <para> OK, I'll stop ranting now, and get back to the tutorial.
</para>
+ <para>
+ This tutorial concentrates upon one particular piece of functionality:
placing a hotel reservation. From the user's perspective, hotel search, selection,
booking, and confirmation are one continuous unit of work — a
<emphasis>conversation</emphasis>. However, from our perspective, it is
important that searching remains separate so that users can select multiple hotels from
the same search results page, and open distinct conversations in separate browswer tabs.
+ </para>
+ <para>
+ Most web application architectures do not have first class constructs to
represent conversations, which makes managing conversational state problematic. Java web
applications generally use a combination of several techniques. Some state is transferred
in the URL, but what cannot be transferred here is either added to the
<literal>HttpSession</literal> or recorded to the database at the beginning
and end of each request.
+ </para>
+ <para>
+ Since the database is the least-scalable tier, this drastically reduces
scalability. The extra traffic to and from the database also increases latency. In order
to reduce redundant traffic, Java applications often introduce a data cache to store
commonly-accessed data between requests. However, since invalidation is based upon an LRU
policy, rather than whether the user has finished using the data, this cache is
inefficient. It is also shared between concurrent transactions, which introduces further
issues associated with keeping the cached state consistent with that of the database.
+ </para>
+ <para>
+ State held in the <literal>HttpSession</literal> suffers
similar issues. The <literal>HttpSession</literal> is fine for storing true
session data — data common to all requests between user and application — but for data
related to individual request series, it does not work so well. Conversations stored here
quickly break down when dealing with multiple windows or the back button. Without careful
programming, data in the <literal>HttpSession</literal> can also grow quite
large, which makes the session difficult to cluster. Developing mechanisms to deal with
the problems these methods present (by isolating session state associated with distinct
concurrent conversations, and incorporating failsafes to ensure conversation state is
destroyed when a conversation is aborted) can be complicated.
+ </para>
+ <para>
+ Seam greatly improves conditions by introducing
<emphasis>conversation context</emphasis> as a first class construct.
Conversation state is stored safely in this context, with a well-defined lifecycle. Even
better, there is no need to push data continually between the application server and the
database; the conversation context is a natural cache for currently-used data.
+ </para>
- <para> The booking example application shows how stateful components
with different scopes can collaborate
- together to achieve complex behaviors. The main page of the booking
application allows the user to
- search for hotels. The search results are kept in the Seam session scope.
When the user navigates to one
- of these hotels, a conversation begins, and a conversation scoped
component calls back to the session
- scoped component to retrieve the selected hotel. </para>
- <para> The booking example also demonstrates the use of RichFaces Ajax
to implement rich client behavior without
- the use of handwritten JavaScript. </para>
+ <para>
+ In the following application, the conversation context is used to store
stateful session beans. These are sometimes regarded as detrimental to scalability, and in
the past, they may have been. However, modern application servers have sophisticated
mechanisms for stateful session bean replication. JBoss AS performs fine-grained
replication, replicating only altered bean attribute values. Used correctly, stateful
session beans pose no scalability problems, but for those uncomfortable or unfamiliar with
the use of stateful session beans, Seam also allows the use of POJOs.
+ </para>
+ <para>
+ The booking example shows one way that stateful components with different
scopes can collaborate to achieve complex behaviors. The main page of the booking
application allows the user to search for hotels. Search results are stored in the Seam
session scope. When the user navigate to a hotel, a conversation begins, and a
conversation scoped component retrieves the selected hotel from the session scoped
component.
+ </para>
+ <para>
+ The booking example also demonstrates the use of RichFaces Ajax to
implement rich client behavior without handwritten JavaScript.
+ </para>
+ <para>
+ The search function is implemented with a session-scoped stateful session
bean, similar to the one used in the message list example.
+ </para>
- <para> The search functionality is implemented using a session-scope
stateful session bean, similar to the
- one we saw in the message list example above. </para>
<formalpara><title>HotelSearchingAction.java
Example</title>
<para>
@@ -2724,7 +2684,7 @@
</programlisting>
- <para> Notice that the example is using page actions for some other
functionality—the login
+ <para> Notice that the example is using page actions for some other
functionality — the login
challenge, and the pageview counter. Also notice the use of a parameter
in the page action method
binding. This is not a standard feature of JSF EL, but Seam lets you use
it, not just for page actions,
but also in JSF method bindings. </para>