[jboss-cvs] jboss-seam/doc/reference/en/modules ...
Gavin King
gavin.king at jboss.com
Tue Jun 19 01:55:48 EDT 2007
User: gavin
Date: 07/06/19 01:55:48
Added: doc/reference/en/modules conversations.xml
Log:
readded
Revision Changes Path
1.33 +5 -13 jboss-seam/doc/reference/en/modules/conversations.xml
(In the diff below, changes in quantity of whitespace are not shown.)
Index: conversations.xml
===================================================================
RCS file: conversations.xml
diff -N conversations.xml
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ conversations.xml 19 Jun 2007 05:55:48 -0000 1.33
@@ -0,0 +1,853 @@
+<chapter id="conversations">
+ <title>Conversations and workspace management</title>
+
+ <para>
+ It's time to understand Seam's conversation model in more detail.
+ </para>
+
+ <para>
+ Historically, the notion of a Seam "conversation" came about as
+ a merger of three different ideas:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ The idea of a <emphasis>workspace</emphasis>, which I
+ encountered in a project for the Victorian government in
+ 2002. In this project I was forced to implement workspace
+ management on top of Struts, an experience I pray never
+ to repeat.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The idea of an <emphasis>application transaction</emphasis>
+ with optimistic semantics, and the realization that existing
+ frameworks based around a stateless architecture could not
+ provide effective management of extended persistence contexts.
+ (The Hibernate team is truly fed up with copping the blame for
+ <literal>LazyInitializationException</literal>s, which are
+ not really Hibernate's fault, but rather the fault of the
+ extremely limiting persistence context model supported by
+ stateless architectures such as the Spring framework or the
+ traditional <emphasis>stateless session facade</emphasis>
+ (anti)pattern in J2EE.)
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The idea of a workflow <emphasis>task</emphasis>.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ By unifying these ideas and providing deep support in the framework,
+ we have a powerful construct that lets us build richer and more efficient
+ applications with less code than before.
+ </para>
+
+ <section>
+ <title>Seam's conversation model</title>
+
+ <para>
+ The examples we have seen so far make use of a very simple
+ conversation model that follows these rules:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ There is always a conversation context active during the
+ apply request values, process validations, update model values,
+ invoke application and render response phases of the JSF request
+ lifecycle.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ At the end of the restore view phase of the JSF request
+ lifecycle, Seam attempts to restore any previous long-running
+ conversation context. If none exists, Seam creates a new
+ temporary conversation context.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ When an <literal>@Begin</literal> method is encountered,
+ the temporary conversation context is promoted to a long
+ running conversation.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ When an <literal>@End</literal> method is encountered,
+ any long-running conversation context is demoted to a
+ temporary conversation.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ At the end of the render response phase of the JSF request
+ lifecycle, Seam stores the contents of a long running
+ conversation context or destroys the contents of a temporary
+ conversation context.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Any faces request (a JSF postback) will propagate the
+ conversation context. By default, non-faces requests (GET
+ requests, for example) do not propagate the conversation
+ context, but see below for more information on this.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ If the JSF request lifecycle is foreshortened by a redirect,
+ Seam transparently stores and restores the current conversation
+ context—unless the conversation was already ended via
+ <literal>@End(beforeRedirect=true)</literal>.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Seam transparently propagates the conversation context across JSF postbacks
+ and redirects. If you don't do anything special, a <emphasis>non-faces request</emphasis>
+ (a GET request for example) will not propagate the conversation context and
+ will be processed in a new temporary conversation. This is usually - but not
+ always - the desired behavior.
+ </para>
+
+ <para>
+ If you want to propagate a Seam conversation across a non-faces request, you
+ need to explicitly code the Seam <emphasis>conversation id</emphasis> as a
+ request parameter:
+ </para>
+
+ <programlisting><![CDATA[<a href="main.jsf?conversationId=#{conversation.id}">Continue</a>]]></programlisting>
+
+ <para>
+ Or, the more JSF-ish:
+ </para>
+
+ <programlisting><![CDATA[<h:outputLink value="main.jsf">
+ <f:param name="conversationId" value="#{conversation.id}"/>
+ <h:outputText value="Continue"/>
+</h:outputLink>]]></programlisting>
+
+ <para>
+ If you use the Seam tag library, this is equivalent:
+ </para>
+
+ <programlisting><![CDATA[<h:outputLink value="main.jsf">
+ <s:conversationId/>
+ <h:outputText value="Continue"/>
+</h:outputLink>]]></programlisting>
+
+ <para>
+ If you wish to disable propagation of the conversation context for a
+ postback, a similar trick is used:
+ </para>
+
+ <programlisting><![CDATA[<h:commandLink action="main" value="Exit">
+ <f:param name="conversationPropagation" value="none"/>
+</h:commandLink>]]></programlisting>
+
+ <para>
+ If you use the Seam tag library, this is equivalent:
+ </para>
+
+ <programlisting><![CDATA[<h:commandLink action="main" value="Exit">
+ <s:conversationPropagation type="none"/>
+</h:commandLink>]]></programlisting>
+
+ <para>
+ Note that disabling conversation context propagation is absolutely not the
+ same thing as ending the conversation.
+ </para>
+
+ <para>
+ The <literal>conversationPropagation</literal> request parameter, or
+ the <literal><s:conversationPropagation></literal> tag may even
+ be used to begin and end conversation, or begin a nested
+ conversation.
+ </para>
+
+ <programlisting><![CDATA[<h:commandLink action="main" value="Exit">
+ <s:conversationPropagation type="end"/>
+</h:commandLink>]]></programlisting>
+
+ <programlisting><![CDATA[<h:commandLink action="main" value="Select Child">
+ <s:conversationPropagation type="nested"/>
+</h:commandLink>]]></programlisting>
+
+ <programlisting><![CDATA[<h:commandLink action="main" value="Select Hotel">
+ <s:conversationPropagation type="begin"/>
+</h:commandLink>]]></programlisting>
+
+ <programlisting><![CDATA[<h:commandLink action="main" value="Select Hotel">
+ <s:conversationPropagation type="join"/>
+</h:commandLink>]]></programlisting>
+
+ <para>
+ This conversation model makes it easy to build applications which
+ behave correctly with respect to multi-window operation. For many
+ applications, this is all that is needed. Some complex applications
+ have either or both of the following additional requirements:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ A conversation spans many smaller units of user interaction,
+ which execute serially or even concurrently. The smaller
+ <emphasis>nested conversations</emphasis> have their own
+ isolated set of conversation state, and also have access to
+ the state of the outer conversation.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The user is able to switch between many conversations
+ within the same browser window. This feature is called
+ <emphasis>workspace management</emphasis>.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ </section>
+
+ <section>
+ <title>Nested conversations</title>
+
+ <para>
+ A nested conversation is created by invoking a method marked
+ <literal>@Begin(nested=true)</literal> inside the scope of an
+ existing conversation. A nested conversation has its own
+ conversation context, and also has read-only access to the
+ context of the outer conversation. (It can read the outer
+ conversation's context variables, but not write to them.)
+ When an <literal>@End</literal> is subsequently encountered,
+ the nested conversation will be destroyed, and the outer
+ conversation will resume, by "popping" the conversation stack.
+ Conversations may be nested to any arbitrary depth.
+ </para>
+
+ <para>
+ Certain user activity (workspace management, or the back button)
+ can cause the outer conversation to be resumed before the inner
+ conversation is ended. In this case it is possible to have
+ multiple concurrent nested conversations belonging to the
+ same outer conversation. If the outer conversation ends before
+ a nested conversation ends, Seam destroys all nested conversation
+ contexts along with the outer context.
+ </para>
+
+ <para>
+ A conversation may be thought of as a <emphasis>continuable state</emphasis>.
+ Nested conversations allow the application to capture a consistent
+ continuable state at various points in a user interaction, thus
+ insuring truly correct behavior in the face of backbuttoning and
+ workspace management.
+ </para>
+
+ <para>
+ TODO: an example to show how a nested conversation prevents bad
+ stuff happening when you backbutton.
+ </para>
+
+ <para>
+ Usually, if a component exists in a parent conversation of the
+ current nested conversation, the nested conversation will use
+ the same instance. Occasionally, it is useful to have a different
+ instance in each nested conversation, so that the component
+ instance that exists in the parent conversation is invisible to
+ its child conversations. You can achieve this behavior by
+ annotating the component <literal>@PerNestedConversation</literal>.
+ </para>
+
+ </section>
+
+ <section>
+ <title>Starting conversations with GET requests</title>
+ <para>
+ JSF does not define any kind of action listener that is triggered
+ when a page is accessed via a non-faces request (for example, a
+ HTTP GET request). This can occur if the user bookmarks the page,
+ or if we navigate to the page via an <literal><h:outputLink></literal>.
+ </para>
+
+ <para>
+ Sometimes we want to begin a conversation immediately the page is
+ accessed. Since there is no JSF action method, we can't solve the problem
+ in the usual way, by annotating the action with <literal>@Begin</literal>.
+ </para>
+
+ <para>
+ A further problem arises if the page needs some state to be fetched
+ into a context variable. We've already seen two ways to solve this
+ problem. If that state is held in a Seam component, we can fetch the
+ state in a <literal>@Create</literal> method. If not, we can define a
+ <literal>@Factory</literal> method for the context variable.
+ </para>
+
+ <para>
+ If none of these options works for you, Seam lets you define a
+ <emphasis>page action</emphasis> in the <literal>pages.xml</literal>
+ file.
+ </para>
+
+ <programlisting><![CDATA[<pages>
+ <page view-id="/messageList.jsp" action="#{messageManager.list}"/>
+ ...
+</pages>]]></programlisting>
+
+ <para>
+ This action method is called at the beginning of the render response
+ phase, any time the page is about to be rendered. If a page action
+ returns a non-null outcome, Seam will process any appropriate JSF and
+ Seam navigation rules, possibly resulting in a completely different page
+ being rendered.
+ </para>
+
+ <para>
+ If <emphasis>all</emphasis> you want to do before rendering the page
+ is begin a conversation, you could use a built-in action method that
+ does just that:
+ </para>
+
+ <programlisting><![CDATA[<pages>
+ <page view-id="/messageList.jsp" action="#{conversation.begin}"/>
+ ...
+</pages>]]></programlisting>
+
+ <para>
+ Note that you can also call this built-in action from a JSF
+ control, and, similarly, you can use
+ <literal>#{conversation.end}</literal> to end conversations.
+ </para>
+
+ <para>
+ If you want more control, to join existing conversations or
+ begin a nested conversion, to begin a pageflow or an atomic
+ conversation, you should use the
+ <literal><begin-conversation></literal> element.
+ </para>
+
+ <programlisting><![CDATA[<pages>
+ <page view-id="/messageList.jsp">
+ <begin-conversation nested="true" pageflow="AddItem"/>
+ <page>
+ ...
+</pages>]]></programlisting>
+
+ <para>
+ There is also an <literal><end-conversation></literal>
+ element.
+ </para>
+
+ <programlisting><![CDATA[<pages>
+ <page view-id="/home.jsp">
+ <end-conversation/>
+ <page>
+ ...
+</pages>]]></programlisting>
+
+ <para>
+ To solve the first problem, we now have five options:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ Annotate the <literal>@Create</literal> method with
+ <literal>@Begin</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Annotate the <literal>@Factory</literal> method with
+ <literal>@Begin</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Annotate the Seam page action method with
+ <literal>@Begin</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Use <literal><begin-conversation></literal> in
+ <literal>pages.xml</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Use <literal>#{conversation.begin}</literal> as
+ the Seam page action method
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ </section>
+
+ <section>
+ <title>Using <literal><s:link></literal> and <literal><s:button></literal></title>
+
+ <para>
+ JSF command links always perform a form submission via JavaScript,
+ which breaks the web browser's "open in new window" or "open in new tab"
+ feature. In plain JSF, you need to use an <literal><h:outputLink></literal>
+ if you need this functionality. But there are two major limitations to
+ <literal><h:outputLink></literal>.
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ JSF provides no way to attach an action listener to an
+ <literal><h:outputLink></literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ JSF does not propagate the selected row of a <literal>DataModel</literal>
+ since there is no actual form submission.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Seam provides the notion of a <emphasis>page action</emphasis> to help
+ solve the first problem, but this does nothing to help us with the second
+ problem. We <emphasis>could</emphasis> work around this by using the
+ RESTful approach of passing a request parameter and requerying
+ for the selected object on the server side. In some cases—such as the
+ Seam blog example application—this is indeed the best approach. The
+ RESTful style supports bookmarking, since it does not require server-side state.
+ In other cases, where we don't care about bookmarks, the use of
+ <literal>@DataModel</literal> and <literal>@DataModelSelection</literal> is
+ just so convenient and transparent!
+ </para>
+
+ <para>
+ To fill in this missing functionality, and to make conversation propagation
+ even simpler to manage, Seam provides the <literal><s:link></literal>
+ JSF tag.
+ </para>
+
+ <para>
+ The link may specify just the JSF view id:
+ </para>
+
+ <programlisting><![CDATA[<s:link view="/login.xhtml" value="Login"/>]]></programlisting>
+
+ <para>
+ Or, it may specify an action method (in which case the action outcome determines
+ the page that results):
+ </para>
+
+ <programlisting><![CDATA[<s:link action="#{login.logout}" value="Logout"/>]]></programlisting>
+
+ <para>
+ If you specify <emphasis>both</emphasis> a JSF view id and an action method, the
+ 'view' will be used <emphasis>unless</emphasis> the action method returns a
+ non-null outcome:
+ </para>
+
+ <programlisting><![CDATA[<s:link view="/loggedOut.xhtml" action="#{login.logout}" value="Logout"/>]]></programlisting>
+
+ <para>
+ The link automatically propagates the selected row of a <literal>DataModel</literal>
+ using inside <literal><h:dataTable></literal>:
+ </para>
+
+ <programlisting><![CDATA[<s:link view="/hotel.xhtml" action="#{hotelSearch.selectHotel}" value="#{hotel.name}"/>]]></programlisting>
+
+ <para>
+ You can leave the scope of an existing conversation:
+ </para>
+
+ <programlisting><![CDATA[<s:link view="/main.xhtml" propagation="none"/>]]></programlisting>
+
+ <para>
+ You can begin, end, or nest conversations:
+ </para>
+
+ <programlisting><![CDATA[<s:link action="#{issueEditor.viewComment}" propagation="nest"/>]]></programlisting>
+
+ <para>
+ If the link begins a conversation, you can even specify a pageflow to be used:
+ </para>
+
+ <programlisting><![CDATA[<s:link action="#{documentEditor.getDocument}" propagation="begin"
+ pageflow="EditDocument"/>]]></programlisting>
+
+ <para>
+ The <literal>taskInstance</literal> attribute if for use in jBPM task lists:
+ </para>
+
+ <programlisting><![CDATA[<s:link action="#{documentApproval.approveOrReject}" taskInstance="#{task}"/>]]></programlisting>
+
+ <para>
+ (See the DVD Store demo application for examples of this.)
+ </para>
+
+ <para>
+ Finally, if you need the "link" to be rendered as a button, use <literal><s:button></literal>:
+ </para>
+
+ <programlisting><![CDATA[<s:button action="#{login.logout}" value="Logout"/>]]></programlisting>
+
+ </section>
+
+ <section>
+ <title>Success messages</title>
+ <para>
+ It is quite common to display a message to the user indicating
+ success or failure of an action. It is convenient to use a JSF
+ <literal>FacesMessage</literal> for this. Unfortunately, a
+ successful action often requires a browser redirect, and JSF
+ does not propagate faces messages across redirects. This makes
+ it quite difficult to display success messages in plain JSF.
+ </para>
+
+ <para>
+ The built in conversation-scoped Seam component named
+ <literal>facesMessages</literal> solves this problem.
+ (You must have the Seam redirect filter installed.)
+ </para>
+
+ <programlisting><![CDATA[@Name("editDocumentAction")
+ at Stateless
+public class EditDocumentBean implements EditDocument {
+ @In EntityManager em;
+ @In Document document;
+ @In FacesMessages facesMessages;
+
+ public String update() {
+ em.merge(document);
+ facesMessages.add("Document updated");
+ }
+}]]></programlisting>
+
+ <para>
+ Any message added to <literal>facesMessages</literal> is
+ used in the very next render response phase for the current
+ conversation. This even works when there is no long-running
+ conversation since Seam preserves even temporary conversation
+ contexts across redirects.
+ </para>
+
+ <para>
+ You can even include JSF EL expressions in a faces message summary:
+ </para>
+
+ <programlisting><![CDATA[facesMessages.add("Document #{document.title} was updated");]]></programlisting>
+
+ <para>
+ You may display the messages in the usual way, for example:
+ </para>
+
+ <programlisting><![CDATA[<h:messages globalOnly="true"/>]]></programlisting>
+
+ </section>
+
+ <section>
+ <title>Using an "explicit" conversation id</title>
+ <para>
+ Ordinarily, Seam generates a meaningless unique id for each conversation
+ in each session. You can customize the id value when you begin the
+ conversation.
+ </para>
+
+ <para>
+ This feature can be used to customize the conversation id generation
+ algorithm like so:
+ </para>
+
+ <programlisting><![CDATA[@Begin(id="#{myConversationIdGenerator.nextId}")
+public void editHotel() { ... }]]></programlisting>
+
+ <para>
+ Or it can be used to assign a meaningful conversation id:
+ </para>
+
+ <programlisting><![CDATA[@Begin(id="hotel#{hotel.id}")
+public String editHotel() { ... }]]></programlisting>
+
+ <programlisting><![CDATA[@Begin(id="hotel#{hotelsDataModel.rowData.id}")
+public String selectHotel() { ... }]]></programlisting>
+
+ <programlisting><![CDATA[@Begin(id="entry#{params['blogId']}")
+public String viewBlogEntry() { ... }]]></programlisting>
+
+ <programlisting><![CDATA[@BeginTask(id="task#{taskInstance.id}")
+public String approveDocument() { ... }]]></programlisting>
+
+ <para>
+ Clearly, these example result in the same conversation id every time
+ a particular hotel, blog or task is selected. So what happens if a conversation
+ with the same conversation id already exists when the new conversation
+ begins? Well, Seam detects the existing conversation and redirects
+ to that conversation without running the <literal>@Begin</literal>
+ method again. This feature helps control the number of workspaces
+ that are created when using workspace management.
+ </para>
+
+ </section>
+
+ <section>
+ <title>Workspace management</title>
+
+ <para>
+ Workspace management is the ability to "switch" conversations in
+ a single window. Seam makes workspace management completely
+ transparent at the level of the Java code. To enable workspace
+ management, all you need to do is:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ Provide <emphasis>description</emphasis> text for each view id
+ (when using JSF or Seam navigation rules) or page node (when using
+ jPDL pageflows). This description text is displayed to the user
+ by the workspace switchers.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Include one or more of the standard workspace switcher JSP
+ or facelets fragments in your pages. The standard fragments
+ support workspace management via a drop down menu, a list
+ of conversations, or breadcrumbs.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <section>
+ <title>Workspace management and JSF navigation</title>
+ <para>
+ When you use JSF or Seam navigation rules, Seam switches to a
+ conversation by restoring the current <literal>view-id</literal>
+ for that conversation. The descriptive text for the
+ workspace is defined in a file called <literal>pages.xml</literal>
+ that Seam expects to find in the <literal>WEB-INF</literal>
+ directory, right next to <literal>faces-config.xml</literal>:
+ </para>
+
+ <programlisting><![CDATA[<pages>
+ <page view-id="/main.xhtml">Search hotels: #{hotelBooking.searchString}</page>
+ <page view-id="/hotel.xhtml">View hotel: #{hotel.name}</page>
+ <page view-id="/book.xhtml">Book hotel: #{hotel.name}</page>
+ <page view-id="/confirm.xhtml">Confirm: #{booking.description}</page>
+</pages>]]></programlisting>
+
+ <para>
+ Note that if this file is missing, the Seam application will
+ continue to work perfectly! The only missing functionality
+ will be the ability to switch workspaces.
+ </para>
+
+ </section>
+
+ <section>
+ <title>Workspace management and jPDL pageflow</title>
+ <para>
+ When you use a jPDL pageflow definition, Seam switches
+ to a conversation by restoring the current jBPM process
+ state. This is a more flexible model since it allows the
+ same <literal>view-id</literal> to have different
+ descriptions depending upon the current
+ <literal><page></literal> node. The description
+ text is defined by the <literal><page></literal>
+ node:
+ </para>
+
+<programlisting><![CDATA[<pageflow-definition name="shopping">
+
+ <start-state name="start">
+ <transition to="browse"/>
+ </start-state>
+
+ <page name="browse" view-id="/browse.xhtml">
+ <description>DVD Search: #{search.searchPattern}</description>
+ <transition to="browse"/>
+ <transition name="checkout" to="checkout"/>
+ </page>
+
+ <page name="checkout" view-id="/checkout.xhtml">
+ <description>Purchase: $#{cart.total}</description>
+ <transition to="checkout"/>
+ <transition name="complete" to="complete"/>
+ </page>
+
+ <page name="complete" view-id="/complete.xhtml">
+ <end-conversation />
+ </page>
+
+</pageflow-definition>]]></programlisting>
+
+ </section>
+
+ <section>
+ <title>The conversation switcher</title>
+
+ <para>
+ Include the following fragment in your JSP or facelets page
+ to get a drop-down menu that lets you switch to any
+ current conversation, or to any other page of the application:
+ </para>
+
+ <programlisting><![CDATA[<h:selectOneMenu value="#{switcher.conversationIdOrOutcome}">
+ <f:selectItem itemLabel="Find Issues" itemValue="findIssue"/>
+ <f:selectItem itemLabel="Create Issue" itemValue="editIssue"/>
+ <f:selectItems value="#{switcher.selectItems}"/>
+</h:selectOneMenu>
+<h:commandButton action="#{switcher.select}" value="Switch"/>]]></programlisting>
+
+ <para>
+ In this example, we have a menu that includes an item for each
+ conversation, together with two additional items that let the
+ user begin a new conversation.
+ </para>
+
+ <mediaobject>
+ <imageobject role="fo">
+ <imagedata fileref="images/switcher.png" align="center"/>
+ </imageobject>
+ <imageobject role="html">
+ <imagedata fileref="../shared/images/switcher.png" align="center"/>
+ </imageobject>
+ </mediaobject>
+
+ </section>
+
+ <section>
+ <title>The conversation list</title>
+
+ <para>
+ The conversation list is very similar to the conversation switcher,
+ except that it is displayed as a table:
+ </para>
+
+ <programlisting><![CDATA[<h:dataTable value="#{conversationList}" var="entry"
+ rendered="#{not empty conversationList}">
+ <h:column>
+ <f:facet name="header">Workspace</f:facet>
+ <h:commandLink action="#{entry.select}" value="#{entry.description}"/>
+ <h:outputText value="[current]" rendered="#{entry.current}"/>
+ </h:column>
+ <h:column>
+ <f:facet name="header">Activity</f:facet>
+ <h:outputText value="#{entry.startDatetime}">
+ <f:convertDateTime type="time" pattern="hh:mm a"/>
+ </h:outputText>
+ <h:outputText value=" - "/>
+ <h:outputText value="#{entry.lastDatetime}">
+ <f:convertDateTime type="time" pattern="hh:mm a"/>
+ </h:outputText>
+ </h:column>
+ <h:column>
+ <f:facet name="header">Action</f:facet>
+ <h:commandButton action="#{entry.select}" value="#{msg.Switch}"/>
+ <h:commandButton action="#{entry.destroy}" value="#{msg.Destroy}"/>
+ </h:column>
+</h:dataTable>]]></programlisting>
+
+ <para>
+ We imagine that you will want to customize this for your own application.
+ </para>
+
+ <mediaobject>
+ <imageobject role="fo">
+ <imagedata fileref="images/list.png" align="center"/>
+ </imageobject>
+ <imageobject role="html">
+ <imagedata fileref="../shared/images/list.png" align="center"/>
+ </imageobject>
+ </mediaobject>
+
+ <para>
+ The conversation list is nice, but it takes up a lot of space on
+ the page, so you probably don't want to put it on <emphasis>every</emphasis>
+ page.
+ </para>
+
+ <para>
+ Notice that the conversation list lets the user destroy workspaces.
+ </para>
+
+ </section>
+
+ <section>
+ <title>Breadcrumbs</title>
+
+ <para>
+ Breadcrumbs are useful in applications which use a nested conversation
+ model. The breadcrumbs are a list of links to conversations in the
+ current conversation stack:
+ </para>
+
+ <programlisting><![CDATA[<ui:repeat value="#{conversationStack}" var="entry">
+ <h:outputText value=" | "/>
+ <h:commandLink value="#{entry.description}" action="#{entry.select}"/>
+</ui:repeat]]></programlisting>
+
+ <mediaobject>
+ <imageobject role="fo">
+ <imagedata fileref="images/breadcrumbs.png" align="center"/>
+ </imageobject>
+ <imageobject role="html">
+ <imagedata fileref="../shared/images/breadcrumbs.png" align="center"/>
+ </imageobject>
+ </mediaobject>
+
+ </section>
+ </section>
+
+ <section>
+ <title>Conversational components and JSF component bindings</title>
+
+ <para>
+ Conversational components have one minor limitation: they cannot be used to hold bindings
+ to JSF components. (We generally prefer not to use this feature of JSF unless absolutely
+ necessary, since it creates a hard dependency from application logic to the view.) On a
+ postback request, component bindings are updated during the Restore View phase,
+ before the Seam conversation context has been restored.
+ </para>
+
+ <para>
+ To work around this use an event scoped component to store the component bindings and inject
+ it into the conversation scoped component that requires it.
+ </para>
+
+ <programlisting><![CDATA[@Name("grid")
+ at Scope(ScopeType.EVENT)
+public class Grid
+{
+ private HtmlPanelGrid htmlPanelGrid;
+
+ // getters and setters
+ ...
+}]]></programlisting>
+
+
+ <programlisting><![CDATA[@Name("gridEditor")
+ at Scope(ScopeType.CONVERSATION)
+public class GridEditor
+{
+ @In(required=false)
+ private Grid grid;
+
+ ...
+}]]></programlisting>
+
+ </section>
+
+</chapter>
\ No newline at end of file
More information about the jboss-cvs-commits
mailing list