[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&#8212;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>&lt;s:conversationPropagation&gt;</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>&lt;h:outputLink&gt;</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>&lt;begin-conversation&gt;</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>&lt;end-conversation&gt;</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>&lt;begin-conversation&gt;</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>&lt;s:link&gt;</literal> and <literal>&lt;s:button&gt;</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>&lt;h:outputLink&gt;</literal>
  +            if you need this functionality. But there are two major limitations to 
  +            <literal>&lt;h:outputLink&gt;</literal>.
  +        </para>
  +        
  +    <itemizedlist>
  +        <listitem>
  +        <para>
  +            JSF provides no way to attach an action listener to an 
  +            <literal>&lt;h:outputLink&gt;</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&#8212;such as the 
  +            Seam blog example application&#8212;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>&lt;s:link&gt;</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>&lt;h:dataTable&gt;</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>&lt;s:button&gt;</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>&lt;page&gt;</literal> node. The description
  +                text is defined by the <literal>&lt;page&gt;</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