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 2009/02/23 22:34:33 UTC

svn commit: r747146 - in /myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/viewController: ViewController.java jsf/ViewControllerPhaseListener.java

Author: skitching
Date: Mon Feb 23 21:34:26 2009
New Revision: 747146

URL: http://svn.apache.org/viewvc?rev=747146&view=rev
Log:
Fix ORCHESTRA-30 : viewcontroller framework does not call initView again when conversation containing ViewController bean is invalidated (ie ViewController bean is deleted. This patch doesn't actually make that happen, but it does make it possible for a backing bean to force the viewcontroller framework to do so (by forcing creation of a new ViewRoot instance).


Modified:
    myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/viewController/ViewController.java
    myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/viewController/jsf/ViewControllerPhaseListener.java

Modified: myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/viewController/ViewController.java
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/viewController/ViewController.java?rev=747146&r1=747145&r2=747146&view=diff
==============================================================================
--- myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/viewController/ViewController.java (original)
+++ myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/viewController/ViewController.java Mon Feb 23 21:34:26 2009
@@ -37,6 +37,31 @@
      * This method will <i>always</i> be called before any other method is invoked
      * on any backing bean for the current request. It is invoked once for each
      * request.
+     * <p>
+     * This callback could possibly be better named "notifyBeginRequestUsingThisView"
+     * or similar, as it is invoked per request.
+     * <p>
+     * There are three different situations in which initView callbacks occur:
+     * <ol>
+     * <li>
+     * A view is just being rendered.<br>
+     * The initView callback gets called once (at BeforeRender)
+     * </li>
+     * <li>
+     * A postback is processed, no navigation occurs.<br>
+     * The initView callback gets called once (at AfterRestoreView)
+     * </li>
+     * <li>
+     * A postback occurs, navigation to a different view instance occurs.<br>
+     * The initView callback gets called once for the original view, and then once for the new view.
+     * </li>
+     * </ol>
+     * <p>
+     * Note that the condition tested is whether the <i>view instance</i> has changed; if navigation causes
+     * a new view root to be created then the initView callback occurs even if that view root has the
+     * same viewId [1].
+     * <p>
+     * Note [1]: Orchestra versions 1.3 and earlier test only the viewId string.
      */
     public void initView();
 

Modified: myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/viewController/jsf/ViewControllerPhaseListener.java
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/viewController/jsf/ViewControllerPhaseListener.java?rev=747146&r1=747145&r2=747146&view=diff
==============================================================================
--- myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/viewController/jsf/ViewControllerPhaseListener.java (original)
+++ myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/viewController/jsf/ViewControllerPhaseListener.java Mon Feb 23 21:34:26 2009
@@ -19,38 +19,43 @@
 
 package org.apache.myfaces.orchestra.viewController.jsf;
 
-import org.apache.myfaces.orchestra.viewController.ViewControllerManagerFactory;
-import org.apache.myfaces.orchestra.viewController.ViewControllerManager;
+import java.util.Set;
+import java.util.TreeSet;
 
 import javax.faces.component.UIViewRoot;
 import javax.faces.context.FacesContext;
 import javax.faces.event.PhaseEvent;
 import javax.faces.event.PhaseId;
 import javax.faces.event.PhaseListener;
-import java.util.Set;
-import java.util.TreeSet;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.myfaces.orchestra.viewController.ViewControllerManager;
+import org.apache.myfaces.orchestra.viewController.ViewControllerManagerFactory;
 
 /**
  * Causes lifecycle methods to be invoked on backing beans that are associated with
  * the current view.
  * <p>
- * Method executeInitView is invoked on the configured ViewControllerManager when ...
+ * For details about when initView callbacks occur, see the documentation for
+ * method initView on class ViewController.
  * <p>
- *
+ * See the javadoc for class ViewControllerManager on how to configure the ViewController
+ * behaviour.
  * <p>
- * See the javadoc for class ViewControllerManager on how to configure this.
+ * Note that at the moment this does not support a ViewController bean for subviews
+ * (ie f:subView tags), which the Shale ViewController framework does provide. ViewController
+ * beans can only be associated with the main viewId, ie the "top level" view template file.
  * <p>
- * Note that at the moment this does not supprt a ViewController bean for subviews
- * (ie f:subView tags), which the Shale ViewController framework does provide.
- * <p>
- * It also might not invoke all the callbacks if exceptions are thrown by actionlisteners,
+ * Note that some callbacks might not be invoked if exceptions are thrown by actionlisteners,
  * etc (which again Shale guarantees). This is particularly important for an "endView"
  * callback, where resources allocated on initView (such as database connections) might
- * be released.
+ * be released. Hopefully this will be implemented in some later Orchestra release.
  */
 public class ViewControllerPhaseListener implements PhaseListener
 {
     private static final long serialVersionUID = -3975277433747722402L;
+    private final Log log = LogFactory.getLog(ViewControllerPhaseListener.class);
 
     /**
      * @since 1.1
@@ -78,7 +83,8 @@
         }
 
         // Try to init the view in every phase, just so we are sure to never miss it.
-        // This skips the actual call if init has already happened.
+        // This skips the actual call if init has already happened for the current
+        // view root instance.
         executeInitView(event.getFacesContext());
 
         if (PhaseId.RENDER_RESPONSE.equals(event.getPhaseId()))
@@ -185,21 +191,43 @@
             return;
         }
 
-        String viewId = getViewId(facesContext);
+        UIViewRoot viewRoot = facesContext.getViewRoot();
+        if (viewRoot == null)
+        {
+            return;
+        }
+
+        String viewId = viewRoot.getViewId();
         if (viewId == null)
         {
             return;
         }
 
-        ViewControllerPhaseListenerState state = getState(facesContext);
+        // Here we keep track of the ViewRoot instances that we have already called initView for,
+        // and if it changes then we call initView again.
+        //
+        // An alternative would be to keep track of the ViewController instance, and call initView
+        // if that instance changes. But this is tricky as this object is often a proxy for the
+        // real object, and may not change even when the target is invalidated and recreated.
 
-        if (state.initedViews.contains(viewId))
+        String viewKey = String.valueOf(System.identityHashCode(viewRoot));
+        ViewControllerPhaseListenerState state = getState(facesContext);
+        if (state.initedViews.contains(viewKey))
         {
-            // already inited
+            // this view instance is already initialized
+            if (log.isDebugEnabled())
+            {
+                log.debug("Skipping already-initialized viewcontroller bean " + viewKey + " for view " + viewId);
+            }
             return;
         }
-        state.initedViews.add(viewId);
 
+        if (log.isDebugEnabled())
+        {
+            log.debug("Initializing viewcontroller bean " + viewKey + " for view " + viewId);
+        }
+
+        state.initedViews.add(viewKey);
         manager.executeInitView(viewId);
     }