You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by we...@apache.org on 2013/04/16 12:45:55 UTC

svn commit: r1468357 - in /myfaces/tobago/trunk: tobago-core/src/main/faces-config/ tobago-core/src/main/java/org/apache/myfaces/tobago/internal/ajax/ tobago-core/src/main/java/org/apache/myfaces/tobago/util/ tobago-example/tobago-example-demo/src/main...

Author: weber
Date: Tue Apr 16 10:45:54 2013
New Revision: 1468357

URL: http://svn.apache.org/r1468357
Log:
TOBAGO-1248 - Navigate to a new view with partialReload (AJAX) - (Support of CODE_RELOAD_REQUIRED)

Added:
    myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/ajax/AjaxNavigationListener.java
    myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/ajax/AjaxNavigationState.java
Modified:
    myfaces/tobago/trunk/tobago-core/src/main/faces-config/faces-config.xml
    myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/ajax/AjaxResponseRenderer.java
    myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/util/ComponentUtils.java
    myfaces/tobago/trunk/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/reference/PartialReloadController.java
    myfaces/tobago/trunk/tobago-example/tobago-example-demo/src/main/webapp/content/50-partial/partial.xhtml

Modified: myfaces/tobago/trunk/tobago-core/src/main/faces-config/faces-config.xml
URL: http://svn.apache.org/viewvc/myfaces/tobago/trunk/tobago-core/src/main/faces-config/faces-config.xml?rev=1468357&r1=1468356&r2=1468357&view=diff
==============================================================================
--- myfaces/tobago/trunk/tobago-core/src/main/faces-config/faces-config.xml (original)
+++ myfaces/tobago/trunk/tobago-core/src/main/faces-config/faces-config.xml Tue Apr 16 10:45:54 2013
@@ -25,6 +25,11 @@
   <application>
     <default-render-kit-id>tobago</default-render-kit-id>
   </application>
+
+  <lifecycle>
+    <phase-listener>org.apache.myfaces.tobago.internal.ajax.AjaxNavigationListener</phase-listener>
+  </lifecycle>
+
   <component>
     <component-type>javax.faces.NamingContainer</component-type>
     <component-class>org.apache.myfaces.tobago.component.UINamingContainer</component-class>

Added: myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/ajax/AjaxNavigationListener.java
URL: http://svn.apache.org/viewvc/myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/ajax/AjaxNavigationListener.java?rev=1468357&view=auto
==============================================================================
--- myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/ajax/AjaxNavigationListener.java (added)
+++ myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/ajax/AjaxNavigationListener.java Tue Apr 16 10:45:54 2013
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.myfaces.tobago.internal.ajax;
+
+import javax.faces.event.PhaseEvent;
+import javax.faces.event.PhaseId;
+import javax.faces.event.PhaseListener;
+
+public class AjaxNavigationListener implements PhaseListener {
+
+  public void afterPhase(PhaseEvent phaseEvent) {
+    if (phaseEvent.getPhaseId() == PhaseId.RESTORE_VIEW) {
+      AjaxNavigationState.storeIncomingView(phaseEvent.getFacesContext());
+    }
+  }
+
+  public void beforePhase(PhaseEvent phaseEvent) {
+    if (phaseEvent.getPhaseId() == PhaseId.RESTORE_VIEW) {
+      AjaxNavigationState.handleNavigation(phaseEvent.getFacesContext());
+    }
+  }
+
+  public PhaseId getPhaseId() {
+    return PhaseId.ANY_PHASE;
+  }
+  
+}

Added: myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/ajax/AjaxNavigationState.java
URL: http://svn.apache.org/viewvc/myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/ajax/AjaxNavigationState.java?rev=1468357&view=auto
==============================================================================
--- myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/ajax/AjaxNavigationState.java (added)
+++ myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/ajax/AjaxNavigationState.java Tue Apr 16 10:45:54 2013
@@ -0,0 +1,154 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.myfaces.tobago.internal.ajax;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.myfaces.tobago.internal.component.AbstractUIPage;
+import org.apache.myfaces.tobago.layout.Measure;
+import org.apache.myfaces.tobago.util.ComponentUtils;
+
+import javax.faces.application.FacesMessage;
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+public class AjaxNavigationState {
+
+  private static final Logger LOG = LoggerFactory.getLogger(AjaxNavigationState.class);
+  
+  private static final String SESSION_KEY = "tobago-AjaxNavigationState";
+
+  private static final String VIEW_ROOT_KEY = "tobago-AjaxNavigationState-VIEW_ROOT_KEY";
+
+  private UIViewRoot viewRoot;
+  
+  private Measure clientWidth;
+  
+  private Measure clientHeight;
+  
+  private Map<String, List<FacesMessage>> messages;
+
+  private AjaxNavigationState(FacesContext facesContext) {
+    ExternalContext externalContext = facesContext.getExternalContext();
+    externalContext.getSessionMap().put(SESSION_KEY, this);
+    viewRoot = facesContext.getViewRoot();
+    // TODO: Save page dimension
+//    AbstractUIPage page = ComponentUtils.findPage((UIViewRoot) externalContext.getRequestMap().get(VIEW_ROOT_KEY));
+//    clientWidth = page.getCurrentWidth();
+//    clientHeight = page.getCurrentHeight();
+    messages = new HashMap<String, List<FacesMessage>>();
+    Iterator<String> iterator = facesContext.getClientIdsWithMessages();
+    while (iterator.hasNext()) {
+      addFacesMessages(facesContext, iterator.next());
+    }
+    addFacesMessages(facesContext, null);
+    if (LOG.isTraceEnabled()) {
+      LOG.trace("Saved viewRoot.getViewId() = \"{}\"", viewRoot.getViewId());
+      LOG.trace("Saved clientWidth = \"{}\"", clientWidth);
+      LOG.trace("Saved clientHeight = \"{}\"", clientHeight);
+      for (Map.Entry<String, List<FacesMessage>> entry : messages.entrySet()) {
+        for (FacesMessage message : entry.getValue()) {
+          LOG.trace("Saved message \"{}\" : \"{}\"", entry.getKey(), message);
+        }
+      }
+    }
+  }
+
+  private void addFacesMessages(FacesContext facesContext, String clientId) {
+    Iterator<FacesMessage> facesMessages = facesContext.getMessages(clientId);
+    while (facesMessages.hasNext()) {
+      addFacesMessage(clientId, facesMessages.next());
+    }
+  }
+
+  private void addFacesMessage(String clientId, FacesMessage facesMessage) {
+    List<FacesMessage> facesMessages = messages.get(clientId);
+    if (facesMessages == null) {
+      facesMessages = new ArrayList<FacesMessage>();
+      messages.put(clientId, facesMessages);
+    }
+    facesMessages.add(facesMessage);
+  }
+
+  private void restoreView(FacesContext facesContext) {
+    facesContext.setViewRoot(viewRoot);
+    Map<String, Object> requestMap = facesContext.getExternalContext().getRequestMap();
+    requestMap.put("tobago-page-clientDimension-width", clientWidth);
+    requestMap.put("tobago-page-clientDimension-height", clientHeight);
+    for (Map.Entry<String, List<FacesMessage>> entry : messages.entrySet()) {
+      for (FacesMessage facesMessage : entry.getValue()) {
+        facesContext.addMessage(entry.getKey(), facesMessage);
+      }
+    }
+    facesContext.renderResponse();
+    if (LOG.isTraceEnabled()) {
+      LOG.trace("Restored viewRoot.getViewId() = \"{}\"", viewRoot.getViewId());
+      LOG.trace("Restored clientWidth = \"{}\"", clientWidth);
+      LOG.trace("Restored clientHeight = \"{}\"", clientHeight);
+      for (Map.Entry<String, List<FacesMessage>> entry : messages.entrySet()) {
+        for (FacesMessage message : entry.getValue()) {
+          LOG.trace("Restored message \"{}\" : \"{}\"", entry.getKey(), message);
+        }
+      }
+    }
+
+  }
+
+  public static void storeIncomingView(FacesContext facesContext) {
+    UIViewRoot viewRoot = facesContext.getViewRoot();
+    LOG.trace("incoming viewId = \"{}\"", viewRoot.getViewId());
+    facesContext.getExternalContext().getRequestMap().put(AjaxNavigationState.VIEW_ROOT_KEY, viewRoot);
+  }
+
+  public static boolean isNavigation(FacesContext facesContext) {
+
+    final UIViewRoot viewRoot = facesContext.getViewRoot();
+    LOG.trace("current viewId = \"{}\"", viewRoot.getViewId());
+
+    ExternalContext externalContext = facesContext.getExternalContext();
+    Map<String, Object> requestMap = externalContext.getRequestMap();
+    UIViewRoot incomingViewRoot = (UIViewRoot) requestMap.get(VIEW_ROOT_KEY);
+    if (viewRoot != incomingViewRoot) {
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("requesting full page reload because of navigation to {} from {}",
+            viewRoot.getViewId(), incomingViewRoot.getViewId());
+      }
+      externalContext.getSessionMap().put(SESSION_KEY, new AjaxNavigationState(facesContext));
+      return true;
+    }
+    return false;
+  }
+
+  public static void handleNavigation(FacesContext facesContext) {
+    Map<String, Object> sessionMap = facesContext.getExternalContext().getSessionMap();
+    AjaxNavigationState navigationState = (AjaxNavigationState) sessionMap.remove(AjaxNavigationState.SESSION_KEY);
+    if (navigationState != null) {
+      navigationState.restoreView(facesContext);
+      LOG.trace("force render requested navigation view");
+    }
+  }
+}

Modified: myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/ajax/AjaxResponseRenderer.java
URL: http://svn.apache.org/viewvc/myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/ajax/AjaxResponseRenderer.java?rev=1468357&r1=1468356&r2=1468357&view=diff
==============================================================================
--- myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/ajax/AjaxResponseRenderer.java (original)
+++ myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/ajax/AjaxResponseRenderer.java Tue Apr 16 10:45:54 2013
@@ -19,6 +19,9 @@
 
 package org.apache.myfaces.tobago.internal.ajax;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import org.apache.myfaces.tobago.component.Attributes;
 import org.apache.myfaces.tobago.internal.util.FacesContextUtils;
 import org.apache.myfaces.tobago.internal.util.ResponseUtils;
@@ -26,8 +29,6 @@ import org.apache.myfaces.tobago.interna
 import org.apache.myfaces.tobago.util.ComponentUtils;
 import org.apache.myfaces.tobago.util.EncodeAjaxCallback;
 import org.apache.myfaces.tobago.util.RequestUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import javax.faces.FactoryFinder;
 import javax.faces.application.StateManager;
@@ -64,44 +65,9 @@ public class AjaxResponseRenderer {
 
   public void renderResponse(FacesContext facesContext) throws IOException {
     final UIViewRoot viewRoot = facesContext.getViewRoot();
-    RenderKitFactory renderFactory = (RenderKitFactory)
-        FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
-    RenderKit renderKit = renderFactory.getRenderKit(
-        facesContext, viewRoot.getRenderKitId());
-
-    LOG.error("TODO: Reimplement AJAX stuff for JSF 2.0");
-/* XXX: reimplement it for JSF 2.0? Works only, when the TobagoLifecycle is active...
-    UIViewRoot incomingViewRoot = (UIViewRoot)
-        facesContext.getExternalContext().getRequestMap().get(TobagoLifecycle.VIEW_ROOT_KEY);
-    if (viewRoot != incomingViewRoot) {
-      if (LOG.isDebugEnabled()) {
-        LOG.debug("requesting full page reload because of navigation to {} from {}",
-            viewRoot.getViewId(), incomingViewRoot.getViewId());
-      }
-      Map sessionMap = facesContext.getExternalContext().getSessionMap();
-      //noinspection unchecked
-      sessionMap.put(TobagoLifecycle.VIEW_ROOT_KEY, viewRoot);
-      List<Object[]> messageHolders = new ArrayList<Object[]>();
-      Iterator clientIds = facesContext.getClientIdsWithMessages();
-      while (clientIds.hasNext()) {
-        String clientId = (String) clientIds.next();
-        Iterator messages = facesContext.getMessages(clientId);
-        while (messages.hasNext()) {
-          Object[] messageHolder = new Object[2];
-          messageHolder[0] = clientId;
-          messageHolder[1] = messages.next();
-          messageHolders.add(messageHolder);
-        }
-      }
-      if (!messageHolders.isEmpty()) {
-        //noinspection unchecked
-        sessionMap.put(TobagoLifecycle.FACES_MESSAGES_KEY, messageHolders);
-      }
-      writeResponse(facesContext, renderKit, true);
-    } else {
-*/
-      writeResponse(facesContext, renderKit, false);
-//    }
+    RenderKitFactory renderFactory = (RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
+    RenderKit renderKit = renderFactory.getRenderKit(facesContext, viewRoot.getRenderKitId());
+    writeResponse(facesContext, renderKit, AjaxNavigationState.isNavigation(facesContext));
   }
 
   private void renderComponent(FacesContext facesContext, RenderKit renderKit, String clientId, UIComponent component)
@@ -111,9 +77,8 @@ public class AjaxResponseRenderer {
 
     facesContext.setResponseWriter(jsonWriter);
 
-    if (LOG.isDebugEnabled()) {
-      LOG.debug("write ajax response for {}", component);
-    }
+    LOG.debug("write ajax response for {}", component);
+
     writer.write("{\n    \"ajaxId\": \"");
     writer.write(clientId);
     writer.write("\",\n");

Modified: myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/util/ComponentUtils.java
URL: http://svn.apache.org/viewvc/myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/util/ComponentUtils.java?rev=1468357&r1=1468356&r2=1468357&view=diff
==============================================================================
--- myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/util/ComponentUtils.java (original)
+++ myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/util/ComponentUtils.java Tue Apr 16 10:45:54 2013
@@ -181,13 +181,17 @@ public class ComponentUtils {
   }
 
   public static AbstractUIPage findPage(UIComponent component) {
-    while (component != null) {
-      if (component instanceof AbstractUIPage) {
-        return (AbstractUIPage) component;
+    if (component instanceof UIViewRoot) {
+      return findPageBreadthFirst(component);
+    } else {
+      while (component != null) {
+        if (component instanceof AbstractUIPage) {
+          return (AbstractUIPage) component;
+        }
+        component = component.getParent();
       }
-      component = component.getParent();
+      return null;
     }
-    return null;
   }
 
   public static AbstractUIPage findPage(FacesContext facesContext) {

Modified: myfaces/tobago/trunk/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/reference/PartialReloadController.java
URL: http://svn.apache.org/viewvc/myfaces/tobago/trunk/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/reference/PartialReloadController.java?rev=1468357&r1=1468356&r2=1468357&view=diff
==============================================================================
--- myfaces/tobago/trunk/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/reference/PartialReloadController.java (original)
+++ myfaces/tobago/trunk/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/reference/PartialReloadController.java Tue Apr 16 10:45:54 2013
@@ -24,6 +24,8 @@ import org.apache.myfaces.tobago.example
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import javax.el.ELContext;
+import javax.el.ValueExpression;
 import javax.faces.context.FacesContext;
 import javax.inject.Inject;
 import java.util.Date;
@@ -73,7 +75,16 @@ public class PartialReloadController {
 
     // in case of both the select control is not processed during lifecycle
     // we need to get the value from the request params
-    navigateAction = (String) facesContext.getExternalContext().getRequestParameterMap().get("page:navSelect");
+//    navigateAction = (String) facesContext.getExternalContext().getRequestParameterMap().get("page:navSelect");
+
+    AjaxUtils.removeAjaxComponent(facesContext, "page:navTest");
+
+    if (navigationState == null) {
+      ELContext elContext = facesContext.getELContext();
+      ValueExpression expression = facesContext.getApplication().getExpressionFactory()
+          .createValueExpression(elContext, "#{navigationState}", NavigationState.class);
+      navigationState = (NavigationState) expression.getValue(elContext);
+    }
 
     LOG.info("navigateAction = \"" + navigateAction + "\"");
     if (navigateAction == null) {

Modified: myfaces/tobago/trunk/tobago-example/tobago-example-demo/src/main/webapp/content/50-partial/partial.xhtml
URL: http://svn.apache.org/viewvc/myfaces/tobago/trunk/tobago-example/tobago-example-demo/src/main/webapp/content/50-partial/partial.xhtml?rev=1468357&r1=1468356&r2=1468357&view=diff
==============================================================================
--- myfaces/tobago/trunk/tobago-example/tobago-example-demo/src/main/webapp/content/50-partial/partial.xhtml (original)
+++ myfaces/tobago/trunk/tobago-example/tobago-example-demo/src/main/webapp/content/50-partial/partial.xhtml Tue Apr 16 10:45:54 2013
@@ -115,13 +115,13 @@
           <tc:gridLayoutConstraint columnSpan="2"/>
         </tc:button>
 
-        <tc:panel>
+        <tc:panel id="navTest">
           <tc:gridLayoutConstraint columnSpan="2"/>
 
           <tx:selectOneChoice fieldId="navSelect" value="#{partialReloadController.navigateAction}" label="On Change">
             <f:facet name="change">
               <!-- XXX value="fixme" should be empty, but it doesn't work with an empty string -->
-              <tc:command action="#{partialReloadController.navigateAction}" renderedPartially="fixme"/>
+              <tc:command action="#{partialReloadController.navigateAction}" renderedPartially="navTest"/>
             </f:facet>
             <f:selectItem itemLabel="Select action" itemValue=""/>
             <f:selectItem itemLabel="Reload left" itemValue="left"/>