You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by mf...@apache.org on 2008/12/11 23:24:19 UTC

svn commit: r725844 - in /myfaces/portlet-bridge/core/trunk_2.0.x: api/src/main/java/javax/portlet/faces/ api/src/main/java/javax/portlet/faces/event/ impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/ impl/src/main/java/org/apache/myfaces/por...

Author: mfreedman
Date: Thu Dec 11 14:24:19 2008
New Revision: 725844

URL: http://svn.apache.org/viewvc?rev=725844&view=rev
Log:
More updates to implement 1st Portlet 2.0 draft.

Added:
    myfaces/portlet-bridge/core/trunk_2.0.x/api/src/main/java/javax/portlet/faces/BridgePublicRenderParameterHandler.java
    myfaces/portlet-bridge/core/trunk_2.0.x/api/src/main/java/javax/portlet/faces/event/EventNavigationResult.java
Removed:
    myfaces/portlet-bridge/core/trunk_2.0.x/api/src/main/java/javax/portlet/faces/event/PublicRenderParametersChangedEvent.java
Modified:
    myfaces/portlet-bridge/core/trunk_2.0.x/api/src/main/java/javax/portlet/faces/Bridge.java
    myfaces/portlet-bridge/core/trunk_2.0.x/api/src/main/java/javax/portlet/faces/BridgeEventHandler.java
    myfaces/portlet-bridge/core/trunk_2.0.x/api/src/main/java/javax/portlet/faces/GenericFacesPortlet.java
    myfaces/portlet-bridge/core/trunk_2.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/BridgeImpl.java
    myfaces/portlet-bridge/core/trunk_2.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java

Modified: myfaces/portlet-bridge/core/trunk_2.0.x/api/src/main/java/javax/portlet/faces/Bridge.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/trunk_2.0.x/api/src/main/java/javax/portlet/faces/Bridge.java?rev=725844&r1=725843&r2=725844&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/trunk_2.0.x/api/src/main/java/javax/portlet/faces/Bridge.java (original)
+++ myfaces/portlet-bridge/core/trunk_2.0.x/api/src/main/java/javax/portlet/faces/Bridge.java Thu Dec 11 14:24:19 2008
@@ -12,6 +12,8 @@
 
 import javax.portlet.ActionRequest;
 import javax.portlet.ActionResponse;
+import javax.portlet.EventRequest;
+import javax.portlet.EventResponse;
 import javax.portlet.PortletConfig;
 import javax.portlet.PortletException;
 import javax.portlet.RenderRequest;
@@ -434,6 +436,23 @@
                              ActionResponse response) throws BridgeDefaultViewNotSpecifiedException, 
                                                              BridgeUninitializedException, 
                                                              BridgeException;
+  
+  /**
+   * Called by the portlet when it wants the bridge to process an event request.
+   * 
+   * @param request
+   *          the request object.
+   * @param response
+   *          the response object.
+   * @throws BridgeUninitializedException
+   *           thrown if the bridge is not initialized.      
+   * @throws BridgeException
+   *           all other internal exceptions are converted to a BridgeException.
+   */
+  public void doFacesRequest(EventRequest request, 
+                             EventResponse response) throws BridgeUninitializedException, 
+                                                               BridgeException;
+
 
   /**
    * Called by the portlet when it wants the bridge to process a render request.

Modified: myfaces/portlet-bridge/core/trunk_2.0.x/api/src/main/java/javax/portlet/faces/BridgeEventHandler.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/trunk_2.0.x/api/src/main/java/javax/portlet/faces/BridgeEventHandler.java?rev=725844&r1=725843&r2=725844&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/trunk_2.0.x/api/src/main/java/javax/portlet/faces/BridgeEventHandler.java (original)
+++ myfaces/portlet-bridge/core/trunk_2.0.x/api/src/main/java/javax/portlet/faces/BridgeEventHandler.java Thu Dec 11 14:24:19 2008
@@ -12,13 +12,51 @@
 
 import javax.faces.context.FacesContext;
 import javax.portlet.Event;
+import javax.portlet.faces.event.EventNavigationResult;
 
 
 /**
- * 
+ * The <code>BridgeEventHandler</code> interface defines the class the bridge relies
+ * on to process portlet events.  Because portlet events have arbitrary payloads
+ * the bridge provides no automated mappings to managed beans.  Instead, the bridge
+ * calls the <code>handleEvent</code> method on the <code>BridgeEventHandler</code> 
+ * instance passed to it (via a <code>PortletContext</code> attrbiute at init time.
+ * This method is expected to update any models based on the event's payload
+ * and then to perform any needed application recomputation to ensure a 
+ * consistent state.  The method is called after the <code>FacesContext</code>
+ * has been established and the <code>Lifecycle</code> has restored the view.<p>
+ * A view navigation can be affected by returning a non-null <code>EventNavigationResult</code>.
+ * Such an object will contain two <code>String</code> values: a fromAction and 
+ * an outcome.  These correspond to the from action and outcomes in Faces
+ * navigation rules.  Using this information the bridge affects the navigation
+ * by calling the Faces <code>NavigationHandler</code>.
  */
 
 public interface BridgeEventHandler
 {
-    public void handleEvent(FacesContext context, Event event);
+  /**
+   * Called by the bridge when it needs to process a portlet event.<p>
+   * 
+   * Because portlet events have arbitrary payloads
+   * the bridge provides no automated mappings to managed beans.  Instead, the bridge
+   * calls the <code>handleEvent</code> method on the <code>BridgeEventHandler</code> 
+   * instance passed to it (via a <code>PortletContext</code> attrbiute at init time.
+   * This method is expected to update any models based on the event's payload
+   * and then to perform any needed application recomputation to ensure a 
+   * consistent state.  The method is called after the <code>FacesContext</code>
+   * has been established and the <code>Lifecycle</code> has restored the view.<p>
+   * A view navigation can be affected by returning a non-null <code>EventNavigationResult</code>.
+   * Such an object will contain two <code>String</code> values: a fromAction and 
+   * an outcome.  These correspond to the from action and outcomes in Faces
+   * navigation rules.  Using this information the bridge affects the navigation
+   * by calling the Faces <code>NavigationHandler</code>.
+   * 
+   * @param context
+   *          current FacesContext. A Lifecycle has been acquired and the current view restored.
+   * @param event
+   *          the portlet event. Other portlet information (request/response) is accessed via the ExternalContext.
+   * @return an object containing the fromAction and outcome of any navigation that resulted from this event.
+   *         If the event doesn't cause a navigation, return null.
+   */
+  public EventNavigationResult handleEvent(FacesContext context, Event event);
 }

Added: myfaces/portlet-bridge/core/trunk_2.0.x/api/src/main/java/javax/portlet/faces/BridgePublicRenderParameterHandler.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/trunk_2.0.x/api/src/main/java/javax/portlet/faces/BridgePublicRenderParameterHandler.java?rev=725844&view=auto
==============================================================================
--- myfaces/portlet-bridge/core/trunk_2.0.x/api/src/main/java/javax/portlet/faces/BridgePublicRenderParameterHandler.java (added)
+++ myfaces/portlet-bridge/core/trunk_2.0.x/api/src/main/java/javax/portlet/faces/BridgePublicRenderParameterHandler.java Thu Dec 11 14:24:19 2008
@@ -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 javax.portlet.faces;
+
+import javax.faces.context.FacesContext;
+import javax.portlet.Event;
+
+
+ /**
+  * The <code>BridgePublicRenderParameterHandler</code> interface defines the class the bridge relies
+  * on to post process portlet public render parameters.  The handler provides the
+  * portlet a means for resynching application state following any model updates
+  * that resulted from the bridge pushing changed public render parameter values
+  * based on declarative mappings.  After the bridge pushes such values the bridge
+  * calls the handler if it has been configured during bridge <code>init()</code>.
+  * Though the FacesContext has been acquired before the portlet is called to 
+  * process these updates, the Lifecycle has not been acquired or run.  Because
+  * of this is is no current active view.  Unlike events, one can't navigate 
+  * based on a public render parameter change.
+  */
+
+public interface BridgePublicRenderParameterHandler
+{
+  /**
+   * Called by the bridge after pushing incoming public render parameter
+   * values into mapped managed beans.  Only called if there is at least
+   * one public render parameter in the incoming request whose value is 
+   * different (updates) the underlying bean.  This give the portlet an
+   * opportunity to perform further computations based on these changes to 
+   * resynchronize its application state.  
+   * 
+   * @param context
+   *          current FacesContext. A Lifecycle has been acquired and the current view restored.
+   */
+  public void processUpdates(FacesContext context);
+}

Modified: myfaces/portlet-bridge/core/trunk_2.0.x/api/src/main/java/javax/portlet/faces/GenericFacesPortlet.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/trunk_2.0.x/api/src/main/java/javax/portlet/faces/GenericFacesPortlet.java?rev=725844&r1=725843&r2=725844&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/trunk_2.0.x/api/src/main/java/javax/portlet/faces/GenericFacesPortlet.java (original)
+++ myfaces/portlet-bridge/core/trunk_2.0.x/api/src/main/java/javax/portlet/faces/GenericFacesPortlet.java Thu Dec 11 14:24:19 2008
@@ -176,6 +176,13 @@
       getPortletContext().setAttribute(Bridge.BRIDGE_PACKAGE_PREFIX + getPortletName() + "." + 
                                        Bridge.BRIDGE_EVENT_HANDLER, eventHandler);
     }
+    
+    BridgePublicRenderParameterHandler prpHandler = getBridgePublicRenderParameterHandler();
+    if (prpHandler != null)
+    {
+      getPortletContext().setAttribute(Bridge.BRIDGE_PACKAGE_PREFIX + getPortletName() + "." + 
+                                       Bridge.BRIDGE_PUBLIC_RENDER_PARAMETER_HANDLER, prpHandler);
+    }
 
     // Don't instanciate/initialize the bridge yet. Do it on first use
   }
@@ -293,6 +300,45 @@
 
     return null;
   }
+  
+  /**
+   * Returns an instance of a BridgePublicRenderParameterHandler used to post
+   * process public render parameter changes that the bridge
+   * has pushed into mapped models.
+   * This default implementation looks for a portlet initParameter that
+   * names the class used to instantiate the handler.
+   * @return an instance of BridgeRenderParameterHandler or null if there is none.
+   */
+  public BridgePublicRenderParameterHandler getBridgePublicRenderParameterHandler()
+  {
+    String prpHandlerClass = 
+      getPortletConfig().getInitParameter(Bridge.BRIDGE_PACKAGE_PREFIX + Bridge.BRIDGE_PUBLIC_RENDER_PARAMETER_HANDLER);
+    if (prpHandlerClass != null)
+    {
+      try
+      {
+        ClassLoader loader = Thread.currentThread().getContextClassLoader();
+        Class<? extends BridgePublicRenderParameterHandler> c = 
+          (Class<? extends BridgePublicRenderParameterHandler>) loader.loadClass(prpHandlerClass);
+        return c.newInstance();
+      } catch (ClassNotFoundException cnfe)
+      {
+        // Do nothing and fall through to null check
+        // TODO: log something
+      } catch (InstantiationException ie)
+      {
+        // Do nothing and fall through to null check
+        // TODO: log something
+      } catch (Exception e)
+      {
+        // Do nothing and fall through to null check
+        // TODO: log something
+      }
+    }
+
+    return null;
+  }
+
 
 
   /**

Added: myfaces/portlet-bridge/core/trunk_2.0.x/api/src/main/java/javax/portlet/faces/event/EventNavigationResult.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/trunk_2.0.x/api/src/main/java/javax/portlet/faces/event/EventNavigationResult.java?rev=725844&view=auto
==============================================================================
--- myfaces/portlet-bridge/core/trunk_2.0.x/api/src/main/java/javax/portlet/faces/event/EventNavigationResult.java (added)
+++ myfaces/portlet-bridge/core/trunk_2.0.x/api/src/main/java/javax/portlet/faces/event/EventNavigationResult.java Thu Dec 11 14:24:19 2008
@@ -0,0 +1,102 @@
+/*
+ * 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 javax.portlet.faces.event;
+
+
+/**
+ * An <code>EventNavigationResult</code> is the type of object that can
+ * be returned from a <code>BrdigeEventHandler.handleEvent</code> call.
+ * When it is returned (non-null) it conveys the Faces navigation information
+ * to the bridge that it needs to utilize the Faces <code>NavigationHandler</code>
+ * to evaluate the navigation according to the configured rules.  The
+ * <code>fromAction</code> corresponds to the <code>fromAction</code> string
+ * in the faces-config.xml navigation rule.  The <code>outcome</code> 
+ * corresponds to the <code>outcome</code> string in the navigation rule.
+ */
+
+public class EventNavigationResult extends Object
+{
+    private String mFromAction;
+    private String mOutcome;
+   
+  /**
+   * Null constructor
+   */    
+    public EventNavigationResult()
+    {
+      
+    }
+
+  /**
+   * Constructor which sets the object to the desired fromAction and outcome
+   * 
+   * @param action
+   *       desired fromAction
+   * @param outcome
+   *       desired outcome
+   */     
+    public EventNavigationResult(String action, String outcome)
+    {
+      mFromAction = action;
+      mOutcome = outcome;
+    }
+    
+  /**
+   * Gets the fromAction stored in this object. The <code>fromAction</code>
+   * corresponds to the <code>fromAction</code> string in the faces-config.xml
+   * navigation rule.
+   * 
+   * @return <code>String</code> containing the fromAction
+   */
+    public String getFromAction()
+    {
+      return mFromAction;
+    }
+
+  /**
+   * Sets the fromAction for this object. The <code>fromAction</code>
+   * corresponds to the <code>fromAction</code> string in the faces-config.xml
+   * navigation rule.
+   * 
+   * @param action
+   *       new fromAction
+   */    
+    public void setFromAction(String action)
+    {
+      mFromAction = action;
+    }
+
+  /**
+   * Gets the outcome stored in this object. The <code>outcome</code>
+   * corresponds to the <code>outcome</code> string in the faces-config.xml
+   * navigation rule.
+   * 
+   * @return <code>String</code> containing the fromAction
+   */    
+  public String getOutcome()
+  {
+    return mOutcome;
+  }
+
+  /**
+   * Sets the fromAction for this object. The <code>fromAction</code>
+   * corresponds to the <code>fromAction</code> string in the faces-config.xml
+   * navigation rule.
+   * 
+   * @param outcome
+   *       new outcome
+   */ 
+  public void setOutcome(String outcome)
+  {
+    mOutcome = outcome;
+  }   
+    
+}

Modified: myfaces/portlet-bridge/core/trunk_2.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/BridgeImpl.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/trunk_2.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/BridgeImpl.java?rev=725844&r1=725843&r2=725844&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/trunk_2.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/BridgeImpl.java (original)
+++ myfaces/portlet-bridge/core/trunk_2.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/BridgeImpl.java Thu Dec 11 14:24:19 2008
@@ -61,6 +61,8 @@
 import javax.portlet.ActionRequest;
 import javax.portlet.ActionResponse;
 import javax.portlet.ClientDataRequest;
+import javax.portlet.EventRequest;
+import javax.portlet.EventResponse;
 import javax.portlet.MimeResponse;
 import javax.portlet.PortalContext;
 import javax.portlet.PortletConfig;
@@ -87,7 +89,7 @@
 import javax.portlet.faces.annotation.BridgeRequestScopeAttributeAdded;
 import javax.portlet.faces.annotation.ExcludeFromManagedRequestScope;
 
-import javax.portlet.faces.event.PublicRenderParametersChangedEvent;
+import javax.portlet.faces.event.EventNavigationResult;
 
 import javax.servlet.ServletConfig;
 import javax.servlet.ServletContext;
@@ -267,6 +269,9 @@
     // instanceof which can fail if a portlet container uses a single class
     // to implement both the action and render request/response objects
     request.setAttribute(Bridge.PORTLET_LIFECYCLE_PHASE, Bridge.PortletPhase.ACTION_PHASE);
+    
+    // Set the PortletName for use throughout this request to read portlet specific context attrs
+    request.setAttribute(PORTLET_NAME_ATTRIBUTE, mPortletConfig.getPortletName());
 
     // Set the FacesServletMapping attribute so the ExternalContext can
     // pick it up and use it to reverse map viewIds to paths
@@ -431,6 +436,192 @@
     }
 
   }
+  
+  public void doFacesRequest(EventRequest request, EventResponse response)
+    throws BridgeException,
+           BridgeDefaultViewNotSpecifiedException,
+           BridgeUninitializedException, 
+           NullPointerException
+  {
+    if (!mInitialized)
+      throw new BridgeUninitializedException();
+    else if (request == null || response == null)
+      throw new NullPointerException("request or response parameter is null");
+    
+    // Do nothing if we don't have a BriegeEventHandler
+    if (mEventHandler == null)
+    {
+      // make sure the render parameters are carried forward into the next request
+      response.setRenderParameters(request);
+      // TODO: maybe log something here?
+      return;
+    }
+
+    // First check to see whether this is a non-JSF request
+    if (request.getParameter(Bridge.NONFACES_TARGET_PATH_PARAMETER) != null)
+    {
+      throw new BridgeNotAFacesRequestException("NonFaces target = "
+            + request.getParameter(Bridge.NONFACES_TARGET_PATH_PARAMETER));
+    }
+
+    // must wait until after init to get at the session
+    // since view mode mapping must always exist -- check it
+    StringBuffer keyBuf = new StringBuffer(30);
+    String key = keyBuf.append(Bridge.VIEWID_HISTORY).append(".view").toString();
+    if (request.getPortletSession().getAttribute(key) == null)
+    {
+      initViewHistoryDefaults(request.getPortletSession(), mDefaultViewIdMap);
+    }
+
+    // Set the Portlet lifecycle phase as a request attribute so its
+    // available to Faces extensions -- allowing that code to NOT rely on
+    // instanceof which can fail if a portlet container uses a single class
+    // to implement both the action and render request/response objects
+    request.setAttribute(Bridge.PORTLET_LIFECYCLE_PHASE, Bridge.PortletPhase.EVENT_PHASE);
+    
+    // Set the PortletName for use throughout this request to read portlet specific context attrs
+    request.setAttribute(PORTLET_NAME_ATTRIBUTE, mPortletConfig.getPortletName());
+
+    // Set the FacesServletMapping attribute so the ExternalContext can
+    // pick it up and use it to reverse map viewIds to paths
+    if (mFacesMappings != null)
+    {
+      request.setAttribute(PortletExternalContextImpl.FACES_MAPPING_ATTRIBUTE, mFacesMappings);
+    }
+
+    // cache names of existing request attributes so can exclude them
+    // from being saved in the bridge's request scope. Note: this is done
+    // before
+    // acquiring the FacesContext because its possible (though unlikely)
+    // the application has inserted itself in this process and sets up
+    // needed request attributes.
+    List<String> preExistingAttributes = getRequestAttributes(request);
+    // place on the request for use here and in the servletRequestAttributeListener
+    if (preExistingAttributes != null)
+    {
+      request.setAttribute(PREEXISTING_ATTRIBUTE_NAMES, preExistingAttributes);
+    }
+    
+    // Make sure that at a minimum the current render parameters are carried forward
+    response.setRenderParameters(request);
+
+    FacesContext context = null;
+    String scopeId = request.getParameter(REQUEST_SCOPE_ID_RENDER_PARAM);
+      if (scopeId != null)
+      {
+        // Its possible we didn't detect the mode change but its the wrong scope
+        // as the scope is encoded with the mode -- confirm its right
+        StringBuffer sb = new StringBuffer(10);
+        String modeCheck = sb.append(":").append(request.getPortletMode().toString()).append(":").toString();
+        if (scopeId.indexOf(modeCheck) < 0 )
+        {
+          // scope is for a different mode
+          scopeId = null;
+        }
+      }
+    boolean restoredScope = false;
+    
+    restoredScope = restoreBridgeRequestScopeData(request, scopeId);
+    
+    try
+    {
+      // Get the FacesContext instance for this request
+      context = getFacesContext(request, response, getLifecycle(), null);
+   
+      // in case a prior scope was managed temporarily on the session -- remove it
+      request.getPortletSession().removeAttribute(BRIDGE_PACKAGE_PREFIX + REQUEST_SCOPE_ID_RENDER_PARAM);
+      
+      // process public render parameters -- note pass in the portlet request as this
+      // exposes the PPR where the one in the ExternalContext doesn't
+      processIncomingPublicRenderParameters(context, request);
+      
+      // add self as PhaseListener to prevent action phase from executing (after restoreView)
+      Lifecycle lifecycle = getLifecycle();
+      lifecycle.addPhaseListener(this);
+
+      // For actions we only execute the lifecycle phase
+      lifecycle.execute(context);
+      
+      // call the eventhandler to process
+      EventNavigationResult result = mEventHandler.handleEvent(context, request.getEvent());
+      
+      if (result != null)
+      {
+        context.getApplication().getNavigationHandler().handleNavigation(context, result.getFromAction(), result.getOutcome());
+      }
+
+      finalizeActionResponse(context);
+        
+      // Process any Public Render parameter changes
+      processOutgoingPublicRenderParameters(context, request, response);
+        
+        
+      // Now check to see if we need to save the scope
+      // We don't save scope if the finalizeActionResponse detected 
+      // a mode change
+      Boolean noScope = (Boolean) request.getAttribute(PortletExternalContextImpl.NO_SCOPE);
+      if (noScope == null || noScope.equals(Boolean.FALSE))
+      {
+        
+        // If event occurred before an action we don't have acope yet
+        if (scopeId == null)
+        {
+          scopeId = initBridgeRequestScope(request, response);
+        }
+
+        // Before preserving the request scope data in the bridge's
+        // request scope,
+        // put the Faces view into request scope. This is done because
+        // JSF 1.2 manages the tree save state opaquely exclusively in
+        // the render phase -- I.e. there is no JSF 1.2 way of having
+        // the
+        // bridge manually save and restore the view
+        saveFacesView(context);
+
+        // Because the portlet model doesn't execute its render phase
+        // within the same request scope but Faces does (assumes this),
+        // preserve the request scope data and the Faces view tree at
+        // RequestScope.
+        saveBridgeRequestScopeData(context, scopeId, preExistingAttributes);
+      }
+
+    }
+    catch (Exception e)
+    {
+      mPortletConfig.getPortletContext().log("Exception thrown in doFacesRequest:action", e);
+      if (!(e instanceof BridgeException))
+      {
+        Throwable rootCause = e.getCause();
+        throw new BridgeException(e.getMessage(), rootCause);
+      }
+      else
+      {
+        throw (BridgeException) e;
+      }
+    }
+    finally
+    {
+      dumpScopeId(scopeId, "ACTION_PHASE");
+
+      if (context != null)
+      {
+        // remove the redirect attr so its not carried over to the 
+        // render in environments in which action/render are run in the
+        // same request ctx.  There are two potential attrs -- the one on 
+        // the request holds info if a redirect occurred within this request
+        // The one on the session caches the redirect that occurred during render 
+        // so it can be used in subsequent renders that occur before the action.
+        context.getExternalContext().getRequestMap().remove(BridgeImpl.REDIRECT_VIEWPARAMS);
+        context.getExternalContext().getSessionMap().remove(BridgeImpl.RENDER_REDIRECT_VIEWPARAMS);
+        context.release();
+      }
+      
+      // our servletrequestattributelistener uses this as an indicator of whether 
+      // its actively working on a request -- remove it to indicate we are done
+      request.removeAttribute(Bridge.PORTLET_LIFECYCLE_PHASE);
+    }
+  }
+
 
   public void doFacesRequest(RenderRequest request, RenderResponse response)
     throws BridgeException,
@@ -509,7 +700,7 @@
       // FacesContext in case anything in the context construction relies
       // on these restored values.
       // don't restore scope if mode changed
-      scopeId = request.getParameter(REQUEST_SCOPE_ID_RENDER_PARAM);;
+      scopeId = request.getParameter(REQUEST_SCOPE_ID_RENDER_PARAM);
       if (scopeId != null)
       {
         // Its possible we didn't detect the mode change but its the wrong scope
@@ -670,8 +861,8 @@
     // ViewRoot should always = null in the resourec case
     if (context.getViewRoot() == null)
     {
-      // add self as PhaseListener to prevent action phases from
-      // executing when running in a render (vs. a resource) request
+      // add self as PhaseListener to restore Messages and in the case of 
+      // the render phase, prevent excuting beyond restoreView
       if (BridgeUtil.getPortletRequestPhase() ==  Bridge.PortletPhase.RENDER_PHASE
           && !mappedPublicParams)
          // if public params mapped then run whole lifecycle so values are pushed into view
@@ -755,7 +946,7 @@
       {
         if (BridgeUtil.getPortletRequestPhase() == Bridge.PortletPhase.RESOURCE_PHASE)
         {
-          saveBridgeRequestScopeData(context,scopeId, preExistingAttributes);
+          saveBridgeRequestScopeData(context, scopeId, preExistingAttributes);
         }
         updateViewInfo(context, scopeId);
       }
@@ -853,8 +1044,6 @@
       scopeId = initBridgeRequestScope(request, null);
     }
 
-    restoreBridgeRequestScopeData(request, scopeId);
-
     FacesContext context = null;
     try
     {
@@ -1414,7 +1603,7 @@
     return scopeId;
   }
 
-  private String initBridgeRequestScope(ClientDataRequest request, StateAwareResponse response)
+  private String initBridgeRequestScope(PortletRequest request, StateAwareResponse response)
   {
 
     // Generate an RMI UID, which is a unique identifier WITHIN the local
@@ -1472,6 +1661,26 @@
         requestScopeMap = createRequestScopeMap(portletContext);
         portletContext.setAttribute(REQUEST_SCOPE_MAP, requestScopeMap);
       }
+      
+      if (BridgeUtil.getPortletRequestPhase() == Bridge.PortletPhase.RESOURCE_PHASE)
+      {
+        // Because we didn't restore them at the beginning of the request
+        // Merge any existing scope attributes that weren't written during this request
+        Map<String, Object> existing = requestScopeMap.get(scopeId);
+        if (existing != null)
+        {
+          Iterator<Map.Entry<String, Object>> i = existing.entrySet().iterator();
+          while (i.hasNext())
+          {
+            Map.Entry<String, Object> e = i.next();
+            if (!o.containsKey(e.getKey()))
+            {
+              o.put(e.getKey(), e.getValue());
+            }
+          }
+        }
+      }
+      
       requestScopeMap.put(scopeId, o);
     }
   }
@@ -1951,7 +2160,14 @@
       FacesContext context = event.getFacesContext();
       // Now restore the Faces Messages
       restoreFacesMessageState(context);
-      context.renderResponse();
+      
+      switch (BridgeUtil.getPortletRequestPhase())
+      {
+      case RENDER_PHASE:
+      case EVENT_PHASE:
+        // skip rest of action processing                    
+        context.renderResponse();
+      }
     }
   }
 

Modified: myfaces/portlet-bridge/core/trunk_2.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/trunk_2.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java?rev=725844&r1=725843&r2=725844&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/trunk_2.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java (original)
+++ myfaces/portlet-bridge/core/trunk_2.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java Thu Dec 11 14:24:19 2008
@@ -57,6 +57,7 @@
 import javax.portlet.PortletURL;
 import javax.portlet.RenderResponse;
 import javax.portlet.ResourceURL;
+import javax.portlet.StateAwareResponse;
 import javax.portlet.WindowState;
 import javax.portlet.faces.Bridge;
 import javax.portlet.faces.BridgeDefaultViewNotSpecifiedException;
@@ -370,9 +371,10 @@
       url = baseURL.toString();
       url = url.replaceAll("\\&amp\\;", "&");
     }
-    else
+    else if (getPortletPhase() == Bridge.PortletPhase.ACTION_PHASE ||
+             getPortletPhase() == Bridge.PortletPhase.EVENT_PHASE)
     { // action - write the viewId to navigational state
-      ActionResponse actionResponse = (ActionResponse) getResponse();
+      StateAwareResponse stateResponse = (StateAwareResponse) getResponse();
 
       // set request params into navigational states
       Enumeration<String> list = queryStr.getParameterNames();
@@ -383,7 +385,7 @@
         {
           try
           {
-            actionResponse.setPortletMode(new PortletMode(queryStr.getParameter(param)));
+            stateResponse.setPortletMode(new PortletMode(queryStr.getParameter(param)));
           }
           catch (Exception e)
           {
@@ -401,7 +403,7 @@
         {
           try
           {
-            actionResponse.setWindowState(new WindowState(queryStr.getParameter(param)));
+            stateResponse.setWindowState(new WindowState(queryStr.getParameter(param)));
           }
           catch (Exception e)
           {
@@ -414,7 +416,7 @@
         }
         else
         {
-          actionResponse.setRenderParameter(param, queryStr.getParameter(param));
+          stateResponse.setRenderParameter(param, queryStr.getParameter(param));
         }
       }
     }