You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by sk...@apache.org on 2007/10/31 16:17:10 UTC

svn commit: r590710 - in /myfaces/orchestra/trunk/core/src/site/xdoc: bestPractice.xml conversation.xml

Author: skitching
Date: Wed Oct 31 08:17:10 2007
New Revision: 590710

URL: http://svn.apache.org/viewvc?rev=590710&view=rev
Log:
Update best-practices recommendation. Other minor doc tweaks.

Modified:
    myfaces/orchestra/trunk/core/src/site/xdoc/bestPractice.xml
    myfaces/orchestra/trunk/core/src/site/xdoc/conversation.xml

Modified: myfaces/orchestra/trunk/core/src/site/xdoc/bestPractice.xml
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/core/src/site/xdoc/bestPractice.xml?rev=590710&r1=590709&r2=590710&view=diff
==============================================================================
--- myfaces/orchestra/trunk/core/src/site/xdoc/bestPractice.xml (original)
+++ myfaces/orchestra/trunk/core/src/site/xdoc/bestPractice.xml Wed Oct 31 08:17:10 2007
@@ -33,6 +33,13 @@
 
 			<subsection name="Single Page Conversation With Flash Scope">
 
+				<p>
+					This applies when you have a single page that the user may submit multiple times
+					(eg select an item from a list and click a button, then select a different item
+					and click another button). The state of the page changes after each submit, but
+					this state must be held in memory.
+				</p>
+
 				<p>
 					Write a single managed bean for the view. Configure this bean as belonging
 					to an unnamed "flash" conversation scope and reference it as normal from 
@@ -41,10 +48,10 @@
 
 				<p>
 					The conversation will be started when the bean is first accessed, and will
-					automatically be terminated when navigation to some other page occurs
-					(well, technically when a page is rendered that does not reference this
-					managed bean). If you have an action method that wants to "start fresh"
-					while remaining at the same view, then from the action method call
+					automatically be terminated (ie the bean will be deleted) when navigation
+					to some other page occurs (well, technically when a page is rendered that
+					does not reference this	managed bean). If you have an action method that wants
+					to "start fresh" while remaining at the same view, then from the action method call
 					ConversationUtils.invalidateAndRestartCurrent() to discard the current
 					conversation.
 				</p>
@@ -52,21 +59,30 @@
 				<p>
 					If this bean is named to match the view that it is backing
 					(eg beanname="edit" for the "/edit" viewid), then it is trivial
-					to get "lifecycle events" from Orchestra's ViewController. See the
+					to get "lifecycle events" from Orchestra's ViewController. Even if
+					the bean-name does not match the view, there are ways of configuring
+					things so it still receives the appropriate callbacks. See the
 					ViewController documentation for more information on this.
 				</p>
 
 			</subsection>
 
 			<subsection name="Multi Page Conversation With Flash Scope">
-
+				<p>
+					This applies when you have a set of pages that cooperate together to interact
+					with the user, but where the state used by these pages must be held in memory.
+					Commonly, sequences of pages like this eventually lead to a "save" or "execute"
+					button which then performs an action using the state that was set up by	the user
+					via the preceding pages. Such sequences are sometimes called a "wizard". 
+				</p>
+
 				<p>
 					Use one flash-scoped controller for the whole conversation, plus one simple
-					request-scoped bean per view. For example, if you have three pages then structure
-					things as follows:
+					request-scoped or flash-scoped bean per view. For example, if you have three
+					pages then structure things as follows:
 
 					<ul>
-						<li>Page:purchaseStep1.jsp</li>
+						<li>Page:purchaseStep1.jsp<br/>Bean name: purchaseStep1</li>
 						<li>Page:purchaseStep2.jsp<br/>Bean name: purchaseStep2</li>
 						<li>Page:purchaseStep3.jsp<br/>Bean name: purchaseStep3</li>
 						<li>Conversation bean name: purchaseController</li>
@@ -74,41 +90,72 @@
 				</p>
 
 				<p>
-				The request-scoped beans are used only to check whether the conversation is really running; this avoids
-				problems when users leap into the middle page of a sequence (eg via a bookmark). EL expressions in
-				all of the pages reference the purchaseController object, not the request-scoped beans.
-				</p>
-
-				<p>
-					We have to ensure that the user starts with the start page. Reasons why this might be violated are:
-					<ul>
-						<li>the conversation timed out in the mid of the work</li>
-						<li>the user tampered with the url</li>
-					</ul>
-					To ensure a running conversation, simply add a method called <code>initView()</code>
-					to the purchaseStep2 and purchaseStep3 beans which looks like the following:
-					<pre>
-public void initView()
-{
-    ConversationUtils.ensureConversationRedirect("pagesController", "/startPage.faces");
-}
+				Generally, there is no need to specify a conversationName attribute for these beans,
+				ie the name of the conversation they are in is the same as the name of the bean.
+				</p>
+				<p>
+				The per-view beans handle logic and state that is specific to that page. If there is state needed
+				for the page, then use "flash" scope, otherwise use "request" scope. Inject the controller bean
+				into each per-view bean so that state and logic which is shared between views can be accessed.
+				</p>
+				<p>
+				If there is common logic that each page shares, then that can be defined in an abstract base bean
+				which the per-view beans extend.
+				</p>
+				<p>
+				EL expressions in the pages can reference either the per-view bean or the common controller bean,
+				whichever is appropriate.
+				</p>
+				<p>
+				There are two problems with workflows: 
+					<ul>
+						<li>
+						  <p>
+						  A conversation may timeout in the middle of a conversation
+						  (eg the user goes to lunch, then tries to continue on return), and
+						  </p>
+						</li>
+						<li>
+						  <p>
+						  A user may try to leap into the middle of a conversation (eg via a bookmark)
+						  </p>
+						</li>
+					</ul>
+				With the above recommended structure, each per-view bean except the first one can then
+				check whether the conversation exists and is in an appropriate state for that view.
+				If not, then a navigation to the proper "entry page" for the conversation can be done.
+				</p>
+				<p>
+				The basic check for the existence of the conversation is fairly simple to do in java code:
+					<pre>
+public void initView()
+{
+    ConversationUtils.ensureConversationRedirect("purchaseController", "/purchaseStep1.jsf");
+}
 					</pre>
+				If a set of per-view beans share a common base class then this initView method can be
+				added to the base class, then overridden only in the page that is redirected to
+				("purchaseStep1.jsp" in this example) to prevent circular redirects. This then protects
+				all of the pages from access without a correctly initialised conversation.
+				</p>
+
+				<p>
+					Without this check, when a user leaps into the middle of a conversation, EL expressions
+					will trigger the creation of the missing purchaseController (and its associated conversation)
+					but the bean probably does not have the appropriate state to render the page correctly.
+				</p>
 
-					As noted above, Orchestra's ViewController will invoke "lifecycle events" for a view
-					onto any bean that has a "matching name". Because the request-scoped beans above have
-					names that match the viewid, the initView method on the appropriate bean is called
-					when a request for that view is received, and a check can be made for the existence
-					of the right conversation. Without this check, when a user leaps into the middle
-					of a conversation, EL expressions will trigger the creation of the missing
-					purchaseController (and its associated conversation) but the bean probably does
-					not have the appropriate state to render the page correctly.
+				<p>
+				The orchestra core15 module provides the @ConversationRequire annotation to make this even easier.
 				</p>
 
 				<p>
-					There is no need for a bean to back the first page (purchaseStep1) because it is
-					perfectly valid for the user to enter that page with no existing conversation.
+				Note that this works even when the purchaseController bean (which is in the purchaseController
+				conversation, unless otherwise configured) is injected into the per-view bean. The object
+				injected is actually a proxy, so the conversation is not created until the bean is really
+				referenced.
 				</p>
-
+
 				<p>
 					<b>Notice:</b> There is also a <code>JsfConversationUtils</code>-class which allows
 					you to invoke a navigation rule rather than encoding a url in the call to
@@ -116,9 +163,11 @@
 				</p>
 
 				<p>
-					An alternative to declaring "dummy beans" just to receive lifecycle callbacks
-					is to customise the way the ViewController maps viewids to beannames. In 
-					particular, see the ViewController annotations from the Orchestra core15 module.
+					If the views in a workflow are so simple that there is no logic or state needed, then
+					rather than declaring "dummy beans" just to receive lifecycle callbacks the way the
+					ViewController maps viewids to beannames can be configured. In particular, see the
+					ViewController annotations from the Orchestra core15 module. Having a separate bean
+					for the "entry page" of a workflow is always a good idea however.
 				</p>
 
 			</subsection>
@@ -138,6 +187,27 @@
 
 			</subsection>
 
+			<subsection name="Avoid Session Scope">
+				<p>
+					In almost all cases, using Session scope is a bad idea. All sorts of data goes into
+					sessions, including data from UI frameworks, and sometimes from the servlet engine
+					itself. Instead of using session-scope, put all such beans into a single conversation
+					scope called "session". The most significant benefit from this is that Orchestra's
+					"conversation context" feature now allows a user to open multiple windows to your
+					app without problems; each window has a different "conversation context", and each
+					"conversation context" has a completely independent set of conversations - including
+					all the beans in the "session" conversation. It's almost like the user connecting
+					from two different machines - except that any application login (authentication)
+					data is shared.
+				</p>
+				<p>
+				  There are a few places where real session-scoped data might be appropriate, but not
+				  many. Think whether two separate browser windows for a user really should share that
+				  data. And if they should, then make sure that the shared objects are thread-safe, as
+				  two concurrent requests from two different windows will be using the same instance. 
+				</p>
+			</subsection>
+
 			<subsection name="Component bindings">
 				<p>
 				We recommend you read about <a href="component-bindings.html">component binding and the scoping problem</a>.
@@ -148,4 +218,4 @@
 
 		</section>
 	</body>
-</document>
\ No newline at end of file
+</document>

Modified: myfaces/orchestra/trunk/core/src/site/xdoc/conversation.xml
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/core/src/site/xdoc/conversation.xml?rev=590710&r1=590709&r2=590710&view=diff
==============================================================================
--- myfaces/orchestra/trunk/core/src/site/xdoc/conversation.xml (original)
+++ myfaces/orchestra/trunk/core/src/site/xdoc/conversation.xml Wed Oct 31 08:17:10 2007
@@ -30,8 +30,8 @@
 			<p>
 				Often a logical operation consists of multiple JSF requests to the server.
 				For example, purchasing an insurance policy requires completing a number
-				of related forms (often referred to as a "conversation" or a "dialog"),
-				during which the same java objects need to be kept in memory.
+				of related forms (often referred to as a "conversation", "workflow" or
+				"dialog"), during which the same java objects need to be kept in memory.
 			</p>
 
 			<p>